[infiniband] Use generic base16 functions for SRP
[people/stefanha/gpxe.git] / src / net / infiniband / ib_srp.c
1 /*
2  * Copyright (C) 2009 Fen Systems Ltd <mbrown@fensystems.co.uk>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  *   Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  *   Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in
14  *   the documentation and/or other materials provided with the
15  *   distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 FILE_LICENCE ( BSD2 );
32
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <gpxe/base16.h>
36 #include <gpxe/srp.h>
37 #include <gpxe/infiniband.h>
38 #include <gpxe/ib_cmrc.h>
39 #include <gpxe/ib_srp.h>
40
41 /**
42  * @file
43  *
44  * SCSI RDMA Protocol over Infiniband
45  *
46  */
47
48 /* Disambiguate the various possible EINVALs */
49 #define EINVAL_BYTE_STRING_LEN ( EINVAL | EUNIQ_01 )
50 #define EINVAL_BYTE_STRING ( EINVAL | EUNIQ_02 )
51 #define EINVAL_INTEGER ( EINVAL | EUNIQ_03 )
52 #define EINVAL_RP_TOO_SHORT ( EINVAL | EUNIQ_04 )
53
54 /** IB SRP parse flags */
55 enum ib_srp_parse_flags {
56         IB_SRP_PARSE_REQUIRED = 0x0000,
57         IB_SRP_PARSE_OPTIONAL = 0x8000,
58         IB_SRP_PARSE_FLAG_MASK = 0xf000,
59 };
60
61 /** IB SRP root path parameters */
62 struct ib_srp_root_path {
63         /** SCSI LUN */
64         struct scsi_lun *lun;
65         /** SRP port IDs */
66         struct srp_port_ids *port_ids;
67         /** IB SRP parameters */
68         struct ib_srp_parameters *ib;
69 };
70
71 /**
72  * Parse IB SRP root path byte-string value
73  *
74  * @v rp_comp           Root path component string
75  * @v default_value     Default value to use if component string is empty
76  * @ret value           Value
77  */
78 static int ib_srp_parse_byte_string ( const char *rp_comp, uint8_t *bytes,
79                                       unsigned int size_flags ) {
80         size_t size = ( size_flags & ~IB_SRP_PARSE_FLAG_MASK );
81         size_t rp_comp_len = strlen ( rp_comp );
82         int decoded_size;
83
84         /* Allow optional components to be empty */
85         if ( ( rp_comp_len == 0 ) &&
86              ( size_flags & IB_SRP_PARSE_OPTIONAL ) )
87                 return 0;
88
89         /* Check string length */
90         if ( rp_comp_len != ( 2 * size ) )
91                 return -EINVAL_BYTE_STRING_LEN;
92
93         /* Parse byte string */
94         decoded_size = base16_decode ( rp_comp, bytes );
95         if ( decoded_size < 0 )
96                 return decoded_size;
97         assert ( decoded_size == size );
98
99         return 0;
100 }
101
102 /**
103  * Parse IB SRP root path integer value
104  *
105  * @v rp_comp           Root path component string
106  * @v default_value     Default value to use if component string is empty
107  * @ret value           Value
108  */
109 static int ib_srp_parse_integer ( const char *rp_comp, int default_value ) {
110         int value;
111         char *end;
112
113         value = strtoul ( rp_comp, &end, 16 );
114         if ( *end )
115                 return -EINVAL_INTEGER;
116
117         if ( end == rp_comp )
118                 return default_value;
119
120         return value;
121 }
122
123 /**
124  * Parse IB SRP root path literal component
125  *
126  * @v rp_comp           Root path component string
127  * @v rp                IB SRP root path
128  * @ret rc              Return status code
129  */
130 static int ib_srp_parse_literal ( const char *rp_comp __unused,
131                                   struct ib_srp_root_path *rp __unused ) {
132         /* Ignore */
133         return 0;
134 }
135
136 /**
137  * Parse IB SRP root path source GID
138  *
139  * @v rp_comp           Root path component string
140  * @v rp                IB SRP root path
141  * @ret rc              Return status code
142  */
143 static int ib_srp_parse_sgid ( const char *rp_comp,
144                                struct ib_srp_root_path *rp ) {
145         struct ib_device *ibdev;
146
147         /* Default to the GID of the last opened Infiniband device */
148         if ( ( ibdev = last_opened_ibdev() ) != NULL )
149                 memcpy ( &rp->ib->sgid, &ibdev->gid, sizeof ( rp->ib->sgid ) );
150
151         return ib_srp_parse_byte_string ( rp_comp, rp->ib->sgid.u.bytes,
152                                           ( sizeof ( rp->ib->sgid ) |
153                                             IB_SRP_PARSE_OPTIONAL ) );
154 }
155
156 /**
157  * Parse IB SRP root path initiator identifier extension
158  *
159  * @v rp_comp           Root path component string
160  * @v rp                IB SRP root path
161  * @ret rc              Return status code
162  */
163 static int ib_srp_parse_initiator_id_ext ( const char *rp_comp,
164                                            struct ib_srp_root_path *rp ) {
165         struct ib_srp_initiator_port_id *port_id =
166                 ib_srp_initiator_port_id ( rp->port_ids );
167
168         return ib_srp_parse_byte_string ( rp_comp, port_id->id_ext.u.bytes,
169                                           ( sizeof ( port_id->id_ext ) |
170                                             IB_SRP_PARSE_OPTIONAL ) );
171 }
172
173 /**
174  * Parse IB SRP root path initiator HCA GUID
175  *
176  * @v rp_comp           Root path component string
177  * @v rp                IB SRP root path
178  * @ret rc              Return status code
179  */
180 static int ib_srp_parse_initiator_hca_guid ( const char *rp_comp,
181                                              struct ib_srp_root_path *rp ) {
182         struct ib_srp_initiator_port_id *port_id =
183                 ib_srp_initiator_port_id ( rp->port_ids );
184
185         /* Default to the GUID portion of the source GID */
186         memcpy ( &port_id->hca_guid, &rp->ib->sgid.u.half[1],
187                  sizeof ( port_id->hca_guid ) );
188
189         return ib_srp_parse_byte_string ( rp_comp, port_id->hca_guid.u.bytes,
190                                           ( sizeof ( port_id->hca_guid ) |
191                                             IB_SRP_PARSE_OPTIONAL ) );
192 }
193
194 /**
195  * Parse IB SRP root path destination GID
196  *
197  * @v rp_comp           Root path component string
198  * @v rp                IB SRP root path
199  * @ret rc              Return status code
200  */
201 static int ib_srp_parse_dgid ( const char *rp_comp,
202                                struct ib_srp_root_path *rp ) {
203         return ib_srp_parse_byte_string ( rp_comp, rp->ib->dgid.u.bytes,
204                                           ( sizeof ( rp->ib->dgid ) |
205                                             IB_SRP_PARSE_REQUIRED ) );
206 }
207
208 /**
209  * Parse IB SRP root path partition key
210  *
211  * @v rp_comp           Root path component string
212  * @v rp                IB SRP root path
213  * @ret rc              Return status code
214  */
215 static int ib_srp_parse_pkey ( const char *rp_comp,
216                                struct ib_srp_root_path *rp ) {
217         int pkey;
218
219         if ( ( pkey = ib_srp_parse_integer ( rp_comp, IB_PKEY_DEFAULT ) ) < 0 )
220                 return pkey;
221         rp->ib->pkey = pkey;
222         return 0;
223 }
224
225 /**
226  * Parse IB SRP root path service ID
227  *
228  * @v rp_comp           Root path component string
229  * @v rp                IB SRP root path
230  * @ret rc              Return status code
231  */
232 static int ib_srp_parse_service_id ( const char *rp_comp,
233                                      struct ib_srp_root_path *rp ) {
234         return ib_srp_parse_byte_string ( rp_comp, rp->ib->service_id.u.bytes,
235                                           ( sizeof ( rp->ib->service_id ) |
236                                             IB_SRP_PARSE_REQUIRED ) );
237 }
238
239 /**
240  * Parse IB SRP root path LUN
241  *
242  * @v rp_comp           Root path component string
243  * @v rp                IB SRP root path
244  * @ret rc              Return status code
245  */
246 static int ib_srp_parse_lun ( const char *rp_comp,
247                               struct ib_srp_root_path *rp ) {
248         return scsi_parse_lun ( rp_comp, rp->lun );
249 }
250
251 /**
252  * Parse IB SRP root path target identifier extension
253  *
254  * @v rp_comp           Root path component string
255  * @v rp                IB SRP root path
256  * @ret rc              Return status code
257  */
258 static int ib_srp_parse_target_id_ext ( const char *rp_comp,
259                                         struct ib_srp_root_path *rp ) {
260         struct ib_srp_target_port_id *port_id =
261                 ib_srp_target_port_id ( rp->port_ids );
262
263         return ib_srp_parse_byte_string ( rp_comp, port_id->id_ext.u.bytes,
264                                           ( sizeof ( port_id->id_ext ) |
265                                             IB_SRP_PARSE_REQUIRED ) );
266 }
267
268 /**
269  * Parse IB SRP root path target I/O controller GUID
270  *
271  * @v rp_comp           Root path component string
272  * @v rp                IB SRP root path
273  * @ret rc              Return status code
274  */
275 static int ib_srp_parse_target_ioc_guid ( const char *rp_comp,
276                                           struct ib_srp_root_path *rp ) {
277         struct ib_srp_target_port_id *port_id =
278                 ib_srp_target_port_id ( rp->port_ids );
279
280         return ib_srp_parse_byte_string ( rp_comp, port_id->ioc_guid.u.bytes,
281                                           ( sizeof ( port_id->ioc_guid ) |
282                                             IB_SRP_PARSE_REQUIRED ) );
283 }
284
285 /** IB SRP root path component parser */
286 struct ib_srp_root_path_parser {
287         /**
288          * Parse IB SRP root path component
289          *
290          * @v rp_comp           Root path component string
291          * @v rp                IB SRP root path
292          * @ret rc              Return status code
293          */
294         int ( * parse ) ( const char *rp_comp, struct ib_srp_root_path *rp );
295 };
296
297 /** IB SRP root path components */
298 static struct ib_srp_root_path_parser ib_srp_rp_parser[] = {
299         { ib_srp_parse_literal },
300         { ib_srp_parse_sgid },
301         { ib_srp_parse_initiator_id_ext },
302         { ib_srp_parse_initiator_hca_guid },
303         { ib_srp_parse_dgid },
304         { ib_srp_parse_pkey },
305         { ib_srp_parse_service_id },
306         { ib_srp_parse_lun },
307         { ib_srp_parse_target_id_ext },
308         { ib_srp_parse_target_ioc_guid },
309 };
310
311 /** Number of IB SRP root path components */
312 #define IB_SRP_NUM_RP_COMPONENTS \
313         ( sizeof ( ib_srp_rp_parser ) / sizeof ( ib_srp_rp_parser[0] ) )
314
315 /**
316  * Parse IB SRP root path
317  *
318  * @v srp               SRP device
319  * @v rp_string         Root path
320  * @ret rc              Return status code
321  */
322 static int ib_srp_parse_root_path ( struct srp_device *srp,
323                                     const char *rp_string ) {
324         struct ib_srp_parameters *ib_params = ib_srp_params ( srp );
325         struct ib_srp_root_path rp = {
326                 .lun = &srp->lun,
327                 .port_ids = &srp->port_ids,
328                 .ib = ib_params,
329         };
330         char rp_string_copy[ strlen ( rp_string ) + 1 ];
331         char *rp_comp[IB_SRP_NUM_RP_COMPONENTS];
332         char *rp_string_tmp = rp_string_copy;
333         unsigned int i = 0;
334         int rc;
335
336         /* Split root path into component parts */
337         strcpy ( rp_string_copy, rp_string );
338         while ( 1 ) {
339                 rp_comp[i++] = rp_string_tmp;
340                 if ( i == IB_SRP_NUM_RP_COMPONENTS )
341                         break;
342                 for ( ; *rp_string_tmp != ':' ; rp_string_tmp++ ) {
343                         if ( ! *rp_string_tmp ) {
344                                 DBGC ( srp, "SRP %p root path \"%s\" too "
345                                        "short\n", srp, rp_string );
346                                 return -EINVAL_RP_TOO_SHORT;
347                         }
348                 }
349                 *(rp_string_tmp++) = '\0';
350         }
351
352         /* Parse root path components */
353         for ( i = 0 ; i < IB_SRP_NUM_RP_COMPONENTS ; i++ ) {
354                 if ( ( rc = ib_srp_rp_parser[i].parse ( rp_comp[i],
355                                                         &rp ) ) != 0 ) {
356                         DBGC ( srp, "SRP %p could not parse \"%s\" in root "
357                                "path \"%s\": %s\n", srp, rp_comp[i],
358                                rp_string, strerror ( rc ) );
359                         return rc;
360                 }
361         }
362
363         return 0;
364 }
365
366 /**
367  * Connect IB SRP session
368  *
369  * @v srp               SRP device
370  * @ret rc              Return status code
371  */
372 static int ib_srp_connect ( struct srp_device *srp ) {
373         struct ib_srp_parameters *ib_params = ib_srp_params ( srp );
374         struct ib_device *ibdev;
375         int rc;
376
377         /* Identify Infiniband device */
378         ibdev = find_ibdev ( &ib_params->sgid );
379         if ( ! ibdev ) {
380                 DBGC ( srp, "SRP %p could not identify Infiniband device\n",
381                        srp );
382                 return -ENODEV;
383         }
384
385         /* Configure remaining SRP parameters */
386         srp->memory_handle = ibdev->rdma_key;
387
388         /* Open CMRC socket */
389         if ( ( rc = ib_cmrc_open ( &srp->socket, ibdev, &ib_params->dgid,
390                                    &ib_params->service_id ) ) != 0 ) {
391                 DBGC ( srp, "SRP %p could not open CMRC socket: %s\n",
392                        srp, strerror ( rc ) );
393                 return rc;
394         }
395
396         return 0;
397 }
398
399 /** IB SRP transport type */
400 struct srp_transport_type ib_srp_transport = {
401         .priv_len = sizeof ( struct ib_srp_parameters ),
402         .parse_root_path = ib_srp_parse_root_path,
403         .connect = ib_srp_connect,
404 };