[infiniband] Allow for the creation of multicast groups
[ipxe.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 <ipxe/interface.h>
36 #include <ipxe/uri.h>
37 #include <ipxe/open.h>
38 #include <ipxe/base16.h>
39 #include <ipxe/acpi.h>
40 #include <ipxe/srp.h>
41 #include <ipxe/infiniband.h>
42 #include <ipxe/ib_cmrc.h>
43 #include <ipxe/ib_srp.h>
44
45 /**
46 * @file
47 *
48 * SCSI RDMA Protocol over Infiniband
49 *
50 */
51
52 /* Disambiguate the various possible EINVALs */
53 #define EINVAL_BYTE_STRING_LEN __einfo_error ( EINFO_EINVAL_BYTE_STRING_LEN )
54 #define EINFO_EINVAL_BYTE_STRING_LEN __einfo_uniqify \
55 ( EINFO_EINVAL, 0x01, "Invalid byte string length" )
56 #define EINVAL_INTEGER __einfo_error ( EINFO_EINVAL_INTEGER )
57 #define EINFO_EINVAL_INTEGER __einfo_uniqify \
58 ( EINFO_EINVAL, 0x03, "Invalid integer" )
59 #define EINVAL_RP_TOO_SHORT __einfo_error ( EINFO_EINVAL_RP_TOO_SHORT )
60 #define EINFO_EINVAL_RP_TOO_SHORT __einfo_uniqify \
61 ( EINFO_EINVAL, 0x04, "Root path too short" )
62
63 /******************************************************************************
64 *
65 * IB SRP devices
66 *
67 ******************************************************************************
68 */
69
70 /** An Infiniband SRP device */
71 struct ib_srp_device {
72 /** Reference count */
73 struct refcnt refcnt;
74
75 /** SRP transport interface */
76 struct interface srp;
77 /** CMRC interface */
78 struct interface cmrc;
79
80 /** Infiniband device */
81 struct ib_device *ibdev;
82
83 /** Destination GID (for boot firmware table) */
84 union ib_gid dgid;
85 /** Service ID (for boot firmware table) */
86 union ib_guid service_id;
87 };
88
89 /**
90 * Free IB SRP device
91 *
92 * @v refcnt Reference count
93 */
94 static void ib_srp_free ( struct refcnt *refcnt ) {
95 struct ib_srp_device *ib_srp =
96 container_of ( refcnt, struct ib_srp_device, refcnt );
97
98 ibdev_put ( ib_srp->ibdev );
99 free ( ib_srp );
100 }
101
102 /**
103 * Close IB SRP device
104 *
105 * @v ib_srp IB SRP device
106 * @v rc Reason for close
107 */
108 static void ib_srp_close ( struct ib_srp_device *ib_srp, int rc ) {
109
110 /* Shut down interfaces */
111 intf_shutdown ( &ib_srp->cmrc, rc );
112 intf_shutdown ( &ib_srp->srp, rc );
113 }
114
115 /**
116 * Describe IB SRP device in an ACPI table
117 *
118 * @v srpdev SRP device
119 * @v acpi ACPI table
120 * @v len Length of ACPI table
121 * @ret rc Return status code
122 */
123 static int ib_srp_describe ( struct ib_srp_device *ib_srp,
124 struct acpi_description_header *acpi,
125 size_t len ) {
126 struct ib_device *ibdev = ib_srp->ibdev;
127 struct sbft_table *sbft =
128 container_of ( acpi, struct sbft_table, acpi );
129 struct sbft_ib_subtable *ib_sbft;
130 size_t used;
131
132 /* Sanity check */
133 if ( acpi->signature != SBFT_SIG )
134 return -EINVAL;
135
136 /* Append IB subtable to existing table */
137 used = le32_to_cpu ( sbft->acpi.length );
138 sbft->ib_offset = cpu_to_le16 ( used );
139 ib_sbft = ( ( ( void * ) sbft ) + used );
140 used += sizeof ( *ib_sbft );
141 if ( used > len )
142 return -ENOBUFS;
143 sbft->acpi.length = cpu_to_le32 ( used );
144
145 /* Populate subtable */
146 memcpy ( &ib_sbft->sgid, &ibdev->gid, sizeof ( ib_sbft->sgid ) );
147 memcpy ( &ib_sbft->dgid, &ib_srp->dgid, sizeof ( ib_sbft->dgid ) );
148 memcpy ( &ib_sbft->service_id, &ib_srp->service_id,
149 sizeof ( ib_sbft->service_id ) );
150 ib_sbft->pkey = cpu_to_le16 ( ibdev->pkey );
151
152 return 0;
153 }
154
155 /** IB SRP CMRC interface operations */
156 static struct interface_operation ib_srp_cmrc_op[] = {
157 INTF_OP ( intf_close, struct ib_srp_device *, ib_srp_close ),
158 };
159
160 /** IB SRP CMRC interface descriptor */
161 static struct interface_descriptor ib_srp_cmrc_desc =
162 INTF_DESC_PASSTHRU ( struct ib_srp_device, cmrc, ib_srp_cmrc_op, srp );
163
164 /** IB SRP SRP interface operations */
165 static struct interface_operation ib_srp_srp_op[] = {
166 INTF_OP ( acpi_describe, struct ib_srp_device *, ib_srp_describe ),
167 INTF_OP ( intf_close, struct ib_srp_device *, ib_srp_close ),
168 };
169
170 /** IB SRP SRP interface descriptor */
171 static struct interface_descriptor ib_srp_srp_desc =
172 INTF_DESC_PASSTHRU ( struct ib_srp_device, srp, ib_srp_srp_op, cmrc );
173
174 /**
175 * Open IB SRP device
176 *
177 * @v block Block control interface
178 * @v ibdev Infiniband device
179 * @v dgid Destination GID
180 * @v service_id Service ID
181 * @v initiator Initiator port ID
182 * @v target Target port ID
183 * @v lun SCSI LUN
184 * @ret rc Return status code
185 */
186 static int ib_srp_open ( struct interface *block, struct ib_device *ibdev,
187 union ib_gid *dgid, union ib_guid *service_id,
188 union srp_port_id *initiator,
189 union srp_port_id *target, struct scsi_lun *lun ) {
190 struct ib_srp_device *ib_srp;
191 int rc;
192
193 /* Allocate and initialise structure */
194 ib_srp = zalloc ( sizeof ( *ib_srp ) );
195 if ( ! ib_srp ) {
196 rc = -ENOMEM;
197 goto err_zalloc;
198 }
199 ref_init ( &ib_srp->refcnt, ib_srp_free );
200 intf_init ( &ib_srp->srp, &ib_srp_srp_desc, &ib_srp->refcnt );
201 intf_init ( &ib_srp->cmrc, &ib_srp_cmrc_desc, &ib_srp->refcnt );
202 ib_srp->ibdev = ibdev_get ( ibdev );
203 DBGC ( ib_srp, "IBSRP %p for " IB_GID_FMT " " IB_GUID_FMT "\n",
204 ib_srp, IB_GID_ARGS ( dgid ), IB_GUID_ARGS ( service_id ) );
205
206 /* Preserve parameters required for boot firmware table */
207 memcpy ( &ib_srp->dgid, dgid, sizeof ( ib_srp->dgid ) );
208 memcpy ( &ib_srp->service_id, service_id,
209 sizeof ( ib_srp->service_id ) );
210
211 /* Open CMRC socket */
212 if ( ( rc = ib_cmrc_open ( &ib_srp->cmrc, ibdev, dgid,
213 service_id ) ) != 0 ) {
214 DBGC ( ib_srp, "IBSRP %p could not open CMRC socket: %s\n",
215 ib_srp, strerror ( rc ) );
216 goto err_cmrc_open;
217 }
218
219 /* Attach SRP device to parent interface */
220 if ( ( rc = srp_open ( block, &ib_srp->srp, initiator, target,
221 ibdev->rdma_key, lun ) ) != 0 ) {
222 DBGC ( ib_srp, "IBSRP %p could not create SRP device: %s\n",
223 ib_srp, strerror ( rc ) );
224 goto err_srp_open;
225 }
226
227 /* Mortalise self and return */
228 ref_put ( &ib_srp->refcnt );
229 return 0;
230
231 err_srp_open:
232 err_cmrc_open:
233 ib_srp_close ( ib_srp, rc );
234 ref_put ( &ib_srp->refcnt );
235 err_zalloc:
236 return rc;
237 }
238
239 /******************************************************************************
240 *
241 * IB SRP URIs
242 *
243 ******************************************************************************
244 */
245
246 /** IB SRP parse flags */
247 enum ib_srp_parse_flags {
248 IB_SRP_PARSE_REQUIRED = 0x0000,
249 IB_SRP_PARSE_OPTIONAL = 0x8000,
250 IB_SRP_PARSE_FLAG_MASK = 0xf000,
251 };
252
253 /** IB SRP root path parameters */
254 struct ib_srp_root_path {
255 /** Source GID */
256 union ib_gid sgid;
257 /** Initiator port ID */
258 union ib_srp_initiator_port_id initiator;
259 /** Destination GID */
260 union ib_gid dgid;
261 /** Partition key */
262 uint16_t pkey;
263 /** Service ID */
264 union ib_guid service_id;
265 /** SCSI LUN */
266 struct scsi_lun lun;
267 /** Target port ID */
268 union ib_srp_target_port_id target;
269 };
270
271 /**
272 * Parse IB SRP root path byte-string value
273 *
274 * @v rp_comp Root path component string
275 * @v default_value Default value to use if component string is empty
276 * @ret value Value
277 */
278 static int ib_srp_parse_byte_string ( const char *rp_comp, uint8_t *bytes,
279 unsigned int size_flags ) {
280 size_t size = ( size_flags & ~IB_SRP_PARSE_FLAG_MASK );
281 size_t rp_comp_len = strlen ( rp_comp );
282 int decoded_size;
283
284 /* Allow optional components to be empty */
285 if ( ( rp_comp_len == 0 ) &&
286 ( size_flags & IB_SRP_PARSE_OPTIONAL ) )
287 return 0;
288
289 /* Check string length */
290 if ( rp_comp_len != ( 2 * size ) )
291 return -EINVAL_BYTE_STRING_LEN;
292
293 /* Parse byte string */
294 decoded_size = base16_decode ( rp_comp, bytes, size );
295 if ( decoded_size < 0 )
296 return decoded_size;
297
298 return 0;
299 }
300
301 /**
302 * Parse IB SRP root path integer value
303 *
304 * @v rp_comp Root path component string
305 * @v default_value Default value to use if component string is empty
306 * @ret value Value
307 */
308 static int ib_srp_parse_integer ( const char *rp_comp, int default_value ) {
309 int value;
310 char *end;
311
312 value = strtoul ( rp_comp, &end, 16 );
313 if ( *end )
314 return -EINVAL_INTEGER;
315
316 if ( end == rp_comp )
317 return default_value;
318
319 return value;
320 }
321
322 /**
323 * Parse IB SRP root path source GID
324 *
325 * @v rp_comp Root path component string
326 * @v rp IB SRP root path
327 * @ret rc Return status code
328 */
329 static int ib_srp_parse_sgid ( const char *rp_comp,
330 struct ib_srp_root_path *rp ) {
331 struct ib_device *ibdev;
332
333 /* Default to the GID of the last opened Infiniband device */
334 if ( ( ibdev = last_opened_ibdev() ) != NULL )
335 memcpy ( &rp->sgid, &ibdev->gid, sizeof ( rp->sgid ) );
336
337 return ib_srp_parse_byte_string ( rp_comp, rp->sgid.bytes,
338 ( sizeof ( rp->sgid ) |
339 IB_SRP_PARSE_OPTIONAL ) );
340 }
341
342 /**
343 * Parse IB SRP root path initiator identifier extension
344 *
345 * @v rp_comp Root path component string
346 * @v rp IB SRP root path
347 * @ret rc Return status code
348 */
349 static int ib_srp_parse_initiator_id_ext ( const char *rp_comp,
350 struct ib_srp_root_path *rp ) {
351 union ib_srp_initiator_port_id *port_id = &rp->initiator;
352
353 return ib_srp_parse_byte_string ( rp_comp, port_id->ib.id_ext.bytes,
354 ( sizeof ( port_id->ib.id_ext ) |
355 IB_SRP_PARSE_OPTIONAL ) );
356 }
357
358 /**
359 * Parse IB SRP root path initiator HCA GUID
360 *
361 * @v rp_comp Root path component string
362 * @v rp IB SRP root path
363 * @ret rc Return status code
364 */
365 static int ib_srp_parse_initiator_hca_guid ( const char *rp_comp,
366 struct ib_srp_root_path *rp ) {
367 union ib_srp_initiator_port_id *port_id = &rp->initiator;
368
369 /* Default to the GUID portion of the source GID */
370 memcpy ( &port_id->ib.hca_guid, &rp->sgid.s.guid,
371 sizeof ( port_id->ib.hca_guid ) );
372
373 return ib_srp_parse_byte_string ( rp_comp, port_id->ib.hca_guid.bytes,
374 ( sizeof ( port_id->ib.hca_guid ) |
375 IB_SRP_PARSE_OPTIONAL ) );
376 }
377
378 /**
379 * Parse IB SRP root path destination GID
380 *
381 * @v rp_comp Root path component string
382 * @v rp IB SRP root path
383 * @ret rc Return status code
384 */
385 static int ib_srp_parse_dgid ( const char *rp_comp,
386 struct ib_srp_root_path *rp ) {
387 return ib_srp_parse_byte_string ( rp_comp, rp->dgid.bytes,
388 ( sizeof ( rp->dgid ) |
389 IB_SRP_PARSE_REQUIRED ) );
390 }
391
392 /**
393 * Parse IB SRP root path partition key
394 *
395 * @v rp_comp Root path component string
396 * @v rp IB SRP root path
397 * @ret rc Return status code
398 */
399 static int ib_srp_parse_pkey ( const char *rp_comp,
400 struct ib_srp_root_path *rp ) {
401 int pkey;
402
403 if ( ( pkey = ib_srp_parse_integer ( rp_comp, IB_PKEY_DEFAULT ) ) < 0 )
404 return pkey;
405 rp->pkey = pkey;
406 return 0;
407 }
408
409 /**
410 * Parse IB SRP root path service ID
411 *
412 * @v rp_comp Root path component string
413 * @v rp IB SRP root path
414 * @ret rc Return status code
415 */
416 static int ib_srp_parse_service_id ( const char *rp_comp,
417 struct ib_srp_root_path *rp ) {
418 return ib_srp_parse_byte_string ( rp_comp, rp->service_id.bytes,
419 ( sizeof ( rp->service_id ) |
420 IB_SRP_PARSE_REQUIRED ) );
421 }
422
423 /**
424 * Parse IB SRP root path LUN
425 *
426 * @v rp_comp Root path component string
427 * @v rp IB SRP root path
428 * @ret rc Return status code
429 */
430 static int ib_srp_parse_lun ( const char *rp_comp,
431 struct ib_srp_root_path *rp ) {
432 return scsi_parse_lun ( rp_comp, &rp->lun );
433 }
434
435 /**
436 * Parse IB SRP root path target identifier extension
437 *
438 * @v rp_comp Root path component string
439 * @v rp IB SRP root path
440 * @ret rc Return status code
441 */
442 static int ib_srp_parse_target_id_ext ( const char *rp_comp,
443 struct ib_srp_root_path *rp ) {
444 union ib_srp_target_port_id *port_id = &rp->target;
445
446 return ib_srp_parse_byte_string ( rp_comp, port_id->ib.id_ext.bytes,
447 ( sizeof ( port_id->ib.id_ext ) |
448 IB_SRP_PARSE_REQUIRED ) );
449 }
450
451 /**
452 * Parse IB SRP root path target I/O controller GUID
453 *
454 * @v rp_comp Root path component string
455 * @v rp IB SRP root path
456 * @ret rc Return status code
457 */
458 static int ib_srp_parse_target_ioc_guid ( const char *rp_comp,
459 struct ib_srp_root_path *rp ) {
460 union ib_srp_target_port_id *port_id = &rp->target;
461
462 return ib_srp_parse_byte_string ( rp_comp, port_id->ib.ioc_guid.bytes,
463 ( sizeof ( port_id->ib.ioc_guid ) |
464 IB_SRP_PARSE_REQUIRED ) );
465 }
466
467 /** IB SRP root path component parser */
468 struct ib_srp_root_path_parser {
469 /**
470 * Parse IB SRP root path component
471 *
472 * @v rp_comp Root path component string
473 * @v rp IB SRP root path
474 * @ret rc Return status code
475 */
476 int ( * parse ) ( const char *rp_comp, struct ib_srp_root_path *rp );
477 };
478
479 /** IB SRP root path components */
480 static struct ib_srp_root_path_parser ib_srp_rp_parser[] = {
481 { ib_srp_parse_sgid },
482 { ib_srp_parse_initiator_id_ext },
483 { ib_srp_parse_initiator_hca_guid },
484 { ib_srp_parse_dgid },
485 { ib_srp_parse_pkey },
486 { ib_srp_parse_service_id },
487 { ib_srp_parse_lun },
488 { ib_srp_parse_target_id_ext },
489 { ib_srp_parse_target_ioc_guid },
490 };
491
492 /** Number of IB SRP root path components */
493 #define IB_SRP_NUM_RP_COMPONENTS \
494 ( sizeof ( ib_srp_rp_parser ) / sizeof ( ib_srp_rp_parser[0] ) )
495
496 /**
497 * Parse IB SRP root path
498 *
499 * @v rp_string Root path string
500 * @v rp IB SRP root path
501 * @ret rc Return status code
502 */
503 static int ib_srp_parse_root_path ( const char *rp_string,
504 struct ib_srp_root_path *rp ) {
505 struct ib_srp_root_path_parser *parser;
506 char rp_string_copy[ strlen ( rp_string ) + 1 ];
507 char *rp_comp[IB_SRP_NUM_RP_COMPONENTS];
508 char *rp_string_tmp = rp_string_copy;
509 unsigned int i = 0;
510 int rc;
511
512 /* Split root path into component parts */
513 strcpy ( rp_string_copy, rp_string );
514 while ( 1 ) {
515 rp_comp[i++] = rp_string_tmp;
516 if ( i == IB_SRP_NUM_RP_COMPONENTS )
517 break;
518 for ( ; *rp_string_tmp != ':' ; rp_string_tmp++ ) {
519 if ( ! *rp_string_tmp ) {
520 DBG ( "IBSRP root path \"%s\" too short\n",
521 rp_string );
522 return -EINVAL_RP_TOO_SHORT;
523 }
524 }
525 *(rp_string_tmp++) = '\0';
526 }
527
528 /* Parse root path components */
529 for ( i = 0 ; i < IB_SRP_NUM_RP_COMPONENTS ; i++ ) {
530 parser = &ib_srp_rp_parser[i];
531 if ( ( rc = parser->parse ( rp_comp[i], rp ) ) != 0 ) {
532 DBG ( "IBSRP could not parse \"%s\" in root path "
533 "\"%s\": %s\n", rp_comp[i], rp_string,
534 strerror ( rc ) );
535 return rc;
536 }
537 }
538
539 return 0;
540 }
541
542 /**
543 * Open IB SRP URI
544 *
545 * @v parent Parent interface
546 * @v uri URI
547 * @ret rc Return status code
548 */
549 static int ib_srp_open_uri ( struct interface *parent, struct uri *uri ) {
550 struct ib_srp_root_path rp;
551 struct ib_device *ibdev;
552 int rc;
553
554 /* Parse URI */
555 if ( ! uri->opaque )
556 return -EINVAL;
557 memset ( &rp, 0, sizeof ( rp ) );
558 if ( ( rc = ib_srp_parse_root_path ( uri->opaque, &rp ) ) != 0 )
559 return rc;
560
561 /* Identify Infiniband device */
562 ibdev = find_ibdev ( &rp.sgid );
563 if ( ! ibdev ) {
564 DBG ( "IBSRP could not identify Infiniband device\n" );
565 return -ENODEV;
566 }
567
568 /* Open IB SRP device */
569 if ( ( rc = ib_srp_open ( parent, ibdev, &rp.dgid, &rp.service_id,
570 &rp.initiator.srp, &rp.target.srp,
571 &rp.lun ) ) != 0 )
572 return rc;
573
574 return 0;
575 }
576
577 /** IB SRP URI opener */
578 struct uri_opener ib_srp_uri_opener __uri_opener = {
579 .scheme = "ib_srp",
580 .open = ib_srp_open_uri,
581 };