2 * Copyright (C) 2009 Fen Systems Ltd <mbrown@fensystems.co.uk>.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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
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.
31 FILE_LICENCE ( BSD2 );
35 #include <ipxe/interface.h>
37 #include <ipxe/open.h>
38 #include <ipxe/base16.h>
39 #include <ipxe/acpi.h>
41 #include <ipxe/infiniband.h>
42 #include <ipxe/ib_cmrc.h>
43 #include <ipxe/ib_srp.h>
48 * SCSI RDMA Protocol over Infiniband
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" )
63 /******************************************************************************
67 ******************************************************************************
70 /** An Infiniband SRP device */
71 struct ib_srp_device {
72 /** Reference count */
75 /** SRP transport interface */
78 struct interface cmrc;
80 /** Infiniband device */
81 struct ib_device *ibdev;
83 /** Destination GID (for boot firmware table) */
85 /** Service ID (for boot firmware table) */
86 union ib_guid service_id;
92 * @v refcnt Reference count
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 );
98 ibdev_put ( ib_srp->ibdev );
103 * Close IB SRP device
105 * @v ib_srp IB SRP device
106 * @v rc Reason for close
108 static void ib_srp_close ( struct ib_srp_device *ib_srp, int rc ) {
110 /* Shut down interfaces */
111 intf_shutdown ( &ib_srp->cmrc, rc );
112 intf_shutdown ( &ib_srp->srp, rc );
116 * Describe IB SRP device in an ACPI table
118 * @v srpdev SRP device
120 * @v len Length of ACPI table
121 * @ret rc Return status code
123 static int ib_srp_describe ( struct ib_srp_device *ib_srp,
124 struct acpi_description_header *acpi,
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;
133 if ( acpi->signature != SBFT_SIG )
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 );
143 sbft->acpi.length = cpu_to_le32 ( used );
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 );
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 ),
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 );
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 ),
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 );
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
184 * @ret rc Return status code
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;
193 /* Allocate and initialise structure */
194 ib_srp = zalloc ( sizeof ( *ib_srp ) );
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 ) );
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 ) );
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 ) );
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 ) );
227 /* Mortalise self and return */
228 ref_put ( &ib_srp->refcnt );
233 ib_srp_close ( ib_srp, rc );
234 ref_put ( &ib_srp->refcnt );
239 /******************************************************************************
243 ******************************************************************************
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,
253 /** IB SRP root path parameters */
254 struct ib_srp_root_path {
257 /** Initiator port ID */
258 union ib_srp_initiator_port_id initiator;
259 /** Destination GID */
264 union ib_guid service_id;
267 /** Target port ID */
268 union ib_srp_target_port_id target;
272 * Parse IB SRP root path byte-string value
274 * @v rp_comp Root path component string
275 * @v default_value Default value to use if component string is empty
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 );
284 /* Allow optional components to be empty */
285 if ( ( rp_comp_len == 0 ) &&
286 ( size_flags & IB_SRP_PARSE_OPTIONAL ) )
289 /* Check string length */
290 if ( rp_comp_len != ( 2 * size ) )
291 return -EINVAL_BYTE_STRING_LEN;
293 /* Parse byte string */
294 decoded_size = base16_decode ( rp_comp, bytes );
295 if ( decoded_size < 0 )
302 * Parse IB SRP root path integer value
304 * @v rp_comp Root path component string
305 * @v default_value Default value to use if component string is empty
308 static int ib_srp_parse_integer ( const char *rp_comp, int default_value ) {
312 value = strtoul ( rp_comp, &end, 16 );
314 return -EINVAL_INTEGER;
316 if ( end == rp_comp )
317 return default_value;
323 * Parse IB SRP root path source GID
325 * @v rp_comp Root path component string
326 * @v rp IB SRP root path
327 * @ret rc Return status code
329 static int ib_srp_parse_sgid ( const char *rp_comp,
330 struct ib_srp_root_path *rp ) {
331 struct ib_device *ibdev;
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 ) );
337 return ib_srp_parse_byte_string ( rp_comp, rp->sgid.bytes,
338 ( sizeof ( rp->sgid ) |
339 IB_SRP_PARSE_OPTIONAL ) );
343 * Parse IB SRP root path initiator identifier extension
345 * @v rp_comp Root path component string
346 * @v rp IB SRP root path
347 * @ret rc Return status code
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;
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 ) );
359 * Parse IB SRP root path initiator HCA GUID
361 * @v rp_comp Root path component string
362 * @v rp IB SRP root path
363 * @ret rc Return status code
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;
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 ) );
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 ) );
379 * Parse IB SRP root path destination GID
381 * @v rp_comp Root path component string
382 * @v rp IB SRP root path
383 * @ret rc Return status code
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 ) );
393 * Parse IB SRP root path partition key
395 * @v rp_comp Root path component string
396 * @v rp IB SRP root path
397 * @ret rc Return status code
399 static int ib_srp_parse_pkey ( const char *rp_comp,
400 struct ib_srp_root_path *rp ) {
403 if ( ( pkey = ib_srp_parse_integer ( rp_comp, IB_PKEY_DEFAULT ) ) < 0 )
410 * Parse IB SRP root path service ID
412 * @v rp_comp Root path component string
413 * @v rp IB SRP root path
414 * @ret rc Return status code
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 ) );
424 * Parse IB SRP root path LUN
426 * @v rp_comp Root path component string
427 * @v rp IB SRP root path
428 * @ret rc Return status code
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 );
436 * Parse IB SRP root path target identifier extension
438 * @v rp_comp Root path component string
439 * @v rp IB SRP root path
440 * @ret rc Return status code
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;
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 ) );
452 * Parse IB SRP root path target I/O controller GUID
454 * @v rp_comp Root path component string
455 * @v rp IB SRP root path
456 * @ret rc Return status code
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;
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 ) );
467 /** IB SRP root path component parser */
468 struct ib_srp_root_path_parser {
470 * Parse IB SRP root path component
472 * @v rp_comp Root path component string
473 * @v rp IB SRP root path
474 * @ret rc Return status code
476 int ( * parse ) ( const char *rp_comp, struct ib_srp_root_path *rp );
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 },
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] ) )
497 * Parse IB SRP root path
499 * @v rp_string Root path string
500 * @v rp IB SRP root path
501 * @ret rc Return status code
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;
512 /* Split root path into component parts */
513 strcpy ( rp_string_copy, rp_string );
515 rp_comp[i++] = rp_string_tmp;
516 if ( i == IB_SRP_NUM_RP_COMPONENTS )
518 for ( ; *rp_string_tmp != ':' ; rp_string_tmp++ ) {
519 if ( ! *rp_string_tmp ) {
520 DBG ( "IBSRP root path \"%s\" too short\n",
522 return -EINVAL_RP_TOO_SHORT;
525 *(rp_string_tmp++) = '\0';
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,
545 * @v parent Parent interface
547 * @ret rc Return status code
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;
557 memset ( &rp, 0, sizeof ( rp ) );
558 if ( ( rc = ib_srp_parse_root_path ( uri->opaque, &rp ) ) != 0 )
561 /* Identify Infiniband device */
562 ibdev = find_ibdev ( &rp.sgid );
564 DBG ( "IBSRP could not identify Infiniband device\n" );
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,
577 /** IB SRP URI opener */
578 struct uri_opener ib_srp_uri_opener __uri_opener = {
580 .open = ib_srp_open_uri,