[infiniband] Pass GMA as a parameter to GMA MAD handlers
[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_gma *gma = &ibdev->gma;
102         struct ib_gid *gid = &av->gid;
103         struct ib_cached_path_record *cached;
104         union ib_mad mad;
105         struct ib_mad_sa *sa = &mad.sa;
106         unsigned int cache_idx;
107         int rc;
108
109         /* Sanity check */
110         if ( ! av->gid_present ) {
111                 DBGC ( gma, "GMA %p attempt to look up path record "
112                        "without GID\n", gma );
113                 return -EINVAL;
114         }
115
116         /* Look in cache for a matching entry */
117         cached = ib_find_path_cache_entry ( ibdev, gid );
118         if ( cached && cached->dlid ) {
119                 /* Populated entry found */
120                 av->lid = cached->dlid;
121                 av->rate = cached->rate;
122                 av->sl = cached->sl;
123                 DBGC2 ( gma, "GMA %p cache hit for %08x:%08x:%08x:%08x\n",
124                         gma, htonl ( gid->u.dwords[0] ),
125                         htonl ( gid->u.dwords[1] ), htonl ( gid->u.dwords[2] ),
126                         htonl ( gid->u.dwords[3] ) );
127                 return 0;
128         }
129         DBGC ( gma, "GMA %p cache miss for %08x:%08x:%08x:%08x%s\n", gma,
130                htonl ( gid->u.dwords[0] ), htonl ( gid->u.dwords[1] ),
131                htonl ( gid->u.dwords[2] ), htonl ( gid->u.dwords[3] ),
132                ( cached ? " (in progress)" : "" ) );
133
134         /* If no unresolved entry was found, then create a new one */
135         if ( ! cached ) {
136                 cache_idx = ( (ib_path_cache_idx++) % IB_NUM_CACHED_PATHS );
137                 cached = &ib_path_cache[cache_idx];
138                 memset ( cached, 0, sizeof ( *cached ) );
139                 memcpy ( &cached->sgid, &ibdev->gid, sizeof ( cached->sgid ) );
140                 memcpy ( &cached->dgid, gid, sizeof ( cached->dgid ) );
141         }
142
143         /* Construct path record request */
144         memset ( sa, 0, sizeof ( *sa ) );
145         sa->mad_hdr.base_version = IB_MGMT_BASE_VERSION;
146         sa->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
147         sa->mad_hdr.class_version = IB_SA_CLASS_VERSION;
148         sa->mad_hdr.method = IB_MGMT_METHOD_GET;
149         sa->mad_hdr.attr_id = htons ( IB_SA_ATTR_PATH_REC );
150         sa->sa_hdr.comp_mask[1] =
151                 htonl ( IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID );
152         memcpy ( &sa->sa_data.path_record.dgid, &cached->dgid,
153                  sizeof ( sa->sa_data.path_record.dgid ) );
154         memcpy ( &sa->sa_data.path_record.sgid, &cached->sgid,
155                  sizeof ( sa->sa_data.path_record.sgid ) );
156
157         /* Issue path record request */
158         if ( ( rc = ib_gma_request ( gma, &mad, NULL, 1 ) ) != 0 ) {
159                 DBGC ( gma, "GMA %p could not get path record: %s\n",
160                        gma, strerror ( rc ) );
161                 return rc;
162         }
163
164         /* Not found yet */
165         return -ENOENT;
166 }
167
168 /**
169  * Handle path record response
170  *
171  * @v gma               General management agent
172  * @v mad               MAD
173  * @ret rc              Return status code
174  */
175 static int ib_handle_path_record ( struct ib_gma *gma,
176                                    union ib_mad *mad ) {
177         struct ib_device *ibdev = gma->ibdev;
178         struct ib_path_record *path_record = &mad->sa.sa_data.path_record;
179         struct ib_gid *dgid = &path_record->dgid;
180         struct ib_cached_path_record *cached;
181         unsigned int dlid;
182         unsigned int sl;
183         unsigned int rate;
184
185         /* Ignore if not a success */
186         if ( mad->hdr.status != htons ( IB_MGMT_STATUS_OK ) ) {
187                 DBGC ( gma, "GMA %p path record lookup failed with status "
188                        "%04x\n", gma, ntohs ( mad->hdr.status ) );
189                 return -EINVAL;
190         }
191
192         /* Extract values from MAD */
193         dlid = ntohs ( path_record->dlid );
194         sl = ( path_record->reserved__sl & 0x0f );
195         rate = ( path_record->rate_selector__rate & 0x3f );
196         DBGC ( gma, "GMA %p path to %08x:%08x:%08x:%08x is %04x sl %d "
197                "rate %d\n", gma, htonl ( dgid->u.dwords[0] ),
198                htonl ( dgid->u.dwords[1] ), htonl ( dgid->u.dwords[2] ),
199                htonl ( dgid->u.dwords[3] ), dlid, sl, rate );
200
201         /* Look for a matching cache entry to fill in */
202         if ( ( cached = ib_find_path_cache_entry ( ibdev, dgid ) ) != NULL ) {
203                 DBGC ( gma, "GMA %p cache add for %08x:%08x:%08x:%08x\n",
204                        gma, htonl ( dgid->u.dwords[0] ),
205                        htonl ( dgid->u.dwords[1] ),
206                        htonl ( dgid->u.dwords[2] ),
207                        htonl ( dgid->u.dwords[3] ) );
208                 cached->dlid = dlid;
209                 cached->rate = rate;
210                 cached->sl = sl;
211         }
212
213         return 0;
214 }
215
216 /** Path record response handler */
217 struct ib_gma_handler ib_path_record_handler __ib_gma_handler = {
218         .mgmt_class = IB_MGMT_CLASS_SUBN_ADM,
219         .class_version = IB_SA_CLASS_VERSION,
220         .method = IB_MGMT_METHOD_GET_RESP,
221         .attr_id = htons ( IB_SA_ATTR_PATH_REC ),
222         .handle = ib_handle_path_record,
223 };