89622d9814cff633f34d36ef290de599078970f7
[people/sha0/gpxe.git] / src / net / infiniband / ib_pathrec.c
1 /*
2  * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
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 <string.h>
23 #include <byteswap.h>
24 #include <errno.h>
25 #include <gpxe/infiniband.h>
26 #include <gpxe/ib_gma.h>
27 #include <gpxe/ib_pathrec.h>
28
29 /** @file
30  *
31  * Infiniband path lookups
32  *
33  */
34
35 /** Number of path record cache entries
36  *
37  * Must be a power of two.
38  */
39 #define IB_NUM_CACHED_PATHS 4
40
41 /** A path record cache entry */
42 struct ib_cached_path_record {
43         /** Infiniband device's port GID
44          *
45          * Used to disambiguate cache entries when we have multiple
46          * Infiniband devices, without having to maintain a pointer to
47          * the Infiniband device.
48          */
49         struct ib_gid sgid;
50         /** Destination GID */
51         struct ib_gid dgid;
52         /** Destination LID */
53         unsigned int dlid;
54         /** Rate */
55         unsigned int rate;
56         /** Service level */
57         unsigned int sl;
58 };
59
60 /** Path record cache */
61 static struct ib_cached_path_record ib_path_cache[IB_NUM_CACHED_PATHS];
62
63 /** Oldest path record cache entry index */
64 static unsigned int ib_path_cache_idx;
65
66 /**
67  * Find path record cache entry
68  *
69  * @v ibdev             Infiniband device
70  * @v dgid              Destination GID
71  * @ret cached          Path record cache entry, or NULL
72  */
73 static struct ib_cached_path_record *
74 ib_find_path_cache_entry ( struct ib_device *ibdev, struct ib_gid *dgid ) {
75         struct ib_cached_path_record *cached;
76         unsigned int i;
77
78         for ( i = 0 ; i < IB_NUM_CACHED_PATHS ; i++ ) {
79                 cached = &ib_path_cache[i];
80                 if ( memcmp ( &cached->sgid, &ibdev->gid,
81                               sizeof ( cached->sgid ) ) != 0 )
82                         continue;
83                 if ( memcmp ( &cached->dgid, dgid,
84                               sizeof ( cached->dgid ) ) != 0 )
85                         continue;
86                 return cached;
87         }
88
89         return NULL;
90 }
91
92 /**
93  * Resolve path record
94  *
95  * @v ibdev             Infiniband device
96  * @v av                Address vector to complete
97  * @ret rc              Return status code
98  */
99 int ib_resolve_path ( struct ib_device *ibdev,
100                       struct ib_address_vector *av ) {
101         struct ib_gid *gid = &av->gid;
102         struct ib_cached_path_record *cached;
103         union ib_mad mad;
104         struct ib_mad_sa *sa = &mad.sa;
105         unsigned int cache_idx;
106         int rc;
107
108         /* Sanity check */
109         if ( ! av->gid_present ) {
110                 DBGC ( ibdev, "IBDEV %p attempt to look up path record "
111                        "without GID\n", ibdev );
112                 return -EINVAL;
113         }
114
115         /* Look in cache for a matching entry */
116         cached = ib_find_path_cache_entry ( ibdev, gid );
117         if ( cached && cached->dlid ) {
118                 /* Populated entry found */
119                 av->lid = cached->dlid;
120                 av->rate = cached->rate;
121                 av->sl = cached->sl;
122                 DBGC2 ( ibdev, "IBDEV %p cache hit for %08x:%08x:%08x:%08x\n",
123                         ibdev, htonl ( gid->u.dwords[0] ),
124                         htonl ( gid->u.dwords[1] ), htonl ( gid->u.dwords[2] ),
125                         htonl ( gid->u.dwords[3] ) );
126                 return 0;
127         }
128         DBGC ( ibdev, "IBDEV %p cache miss for %08x:%08x:%08x:%08x%s\n", ibdev,
129                htonl ( gid->u.dwords[0] ), htonl ( gid->u.dwords[1] ),
130                htonl ( gid->u.dwords[2] ), htonl ( gid->u.dwords[3] ),
131                ( cached ? " (in progress)" : "" ) );
132
133         /* If no unresolved entry was found, then create a new one */
134         if ( ! cached ) {
135                 cache_idx = ( (ib_path_cache_idx++) % IB_NUM_CACHED_PATHS );
136                 cached = &ib_path_cache[cache_idx];
137                 memset ( cached, 0, sizeof ( *cached ) );
138                 memcpy ( &cached->sgid, &ibdev->gid, sizeof ( cached->sgid ) );
139                 memcpy ( &cached->dgid, gid, sizeof ( cached->dgid ) );
140         }
141
142         /* Construct path record request */
143         memset ( sa, 0, sizeof ( *sa ) );
144         sa->mad_hdr.base_version = IB_MGMT_BASE_VERSION;
145         sa->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
146         sa->mad_hdr.class_version = IB_SA_CLASS_VERSION;
147         sa->mad_hdr.method = IB_MGMT_METHOD_GET;
148         sa->mad_hdr.attr_id = htons ( IB_SA_ATTR_PATH_REC );
149         sa->sa_hdr.comp_mask[1] =
150                 htonl ( IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID );
151         memcpy ( &sa->sa_data.path_record.dgid, &cached->dgid,
152                  sizeof ( sa->sa_data.path_record.dgid ) );
153         memcpy ( &sa->sa_data.path_record.sgid, &cached->sgid,
154                  sizeof ( sa->sa_data.path_record.sgid ) );
155
156         /* Issue path record request */
157         if ( ( rc = ib_gma_request ( &ibdev->gma, &mad, NULL ) ) != 0 ) {
158                 DBGC ( ibdev, "IBDEV %p could not get path record: %s\n",
159                        ibdev, strerror ( rc ) );
160                 return rc;
161         }
162
163         /* Not found yet */
164         return -ENOENT;
165 }
166
167 /**
168  * Handle path record response
169  *
170  * @v ibdev             Infiniband device
171  * @v mad               MAD
172  * @ret rc              Return status code
173  */
174 static int ib_handle_path_record ( struct ib_device *ibdev,
175                                    union ib_mad *mad ) {
176         struct ib_path_record *path_record = &mad->sa.sa_data.path_record;
177         struct ib_gid *dgid = &path_record->dgid;
178         struct ib_cached_path_record *cached;
179         unsigned int dlid;
180         unsigned int sl;
181         unsigned int rate;
182
183         /* Ignore if not a success */
184         if ( mad->hdr.status != htons ( IB_MGMT_STATUS_OK ) ) {
185                 DBGC ( ibdev, "IBDEV %p path record lookup failed with status "
186                        "%04x\n", ibdev, ntohs ( mad->hdr.status ) );
187                 return -EINVAL;
188         }
189
190         /* Extract values from MAD */
191         dlid = ntohs ( path_record->dlid );
192         sl = ( path_record->reserved__sl & 0x0f );
193         rate = ( path_record->rate_selector__rate & 0x3f );
194         DBGC ( ibdev, "IBDEV %p path to %08x:%08x:%08x:%08x is %04x sl %d "
195                "rate %d\n", ibdev, htonl ( dgid->u.dwords[0] ),
196                htonl ( dgid->u.dwords[1] ), htonl ( dgid->u.dwords[2] ),
197                htonl ( dgid->u.dwords[3] ), dlid, sl, rate );
198
199         /* Look for a matching cache entry to fill in */
200         if ( ( cached = ib_find_path_cache_entry ( ibdev, dgid ) ) != NULL ) {
201                 DBGC ( ibdev, "IBDEV %p cache add for %08x:%08x:%08x:%08x\n",
202                        ibdev, htonl ( dgid->u.dwords[0] ),
203                        htonl ( dgid->u.dwords[1] ),
204                        htonl ( dgid->u.dwords[2] ),
205                        htonl ( dgid->u.dwords[3] ) );
206                 cached->dlid = dlid;
207                 cached->rate = rate;
208                 cached->sl = sl;
209         }
210
211         return 0;
212 }
213
214 /** Path record response handler */
215 struct ib_mad_handler ib_path_record_handler __ib_mad_handler = {
216         .mgmt_class = IB_MGMT_CLASS_SUBN_ADM,
217         .class_version = IB_SA_CLASS_VERSION,
218         .method = IB_MGMT_METHOD_GET_RESP,
219         .attr_id = htons ( IB_SA_ATTR_PATH_REC ),
220         .handle = ib_handle_path_record,
221 };