Home | History | Annotate | Download | only in infiniband
      1 /*
      2  * Copyright (C) 2009 Fen Systems Ltd <mbrown (at) 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/srp.h>
     36 #include <gpxe/infiniband.h>
     37 #include <gpxe/ib_cmrc.h>
     38 #include <gpxe/ib_srp.h>
     39 
     40 /**
     41  * @file
     42  *
     43  * SCSI RDMA Protocol over Infiniband
     44  *
     45  */
     46 
     47 /* Disambiguate the various possible EINVALs */
     48 #define EINVAL_BYTE_STRING_LEN ( EINVAL | EUNIQ_01 )
     49 #define EINVAL_BYTE_STRING ( EINVAL | EUNIQ_02 )
     50 #define EINVAL_INTEGER ( EINVAL | EUNIQ_03 )
     51 #define EINVAL_RP_TOO_SHORT ( EINVAL | EUNIQ_04 )
     52 
     53 /** IB SRP parse flags */
     54 enum ib_srp_parse_flags {
     55 	IB_SRP_PARSE_REQUIRED = 0x0000,
     56 	IB_SRP_PARSE_OPTIONAL = 0x8000,
     57 	IB_SRP_PARSE_FLAG_MASK = 0xf000,
     58 };
     59 
     60 /** IB SRP root path parameters */
     61 struct ib_srp_root_path {
     62 	/** SCSI LUN */
     63 	struct scsi_lun *lun;
     64 	/** SRP port IDs */
     65 	struct srp_port_ids *port_ids;
     66 	/** IB SRP parameters */
     67 	struct ib_srp_parameters *ib;
     68 };
     69 
     70 /**
     71  * Parse IB SRP root path byte-string value
     72  *
     73  * @v rp_comp		Root path component string
     74  * @v default_value	Default value to use if component string is empty
     75  * @ret value		Value
     76  */
     77 static int ib_srp_parse_byte_string ( const char *rp_comp, uint8_t *bytes,
     78 				      unsigned int size_flags ) {
     79 	size_t size = ( size_flags & ~IB_SRP_PARSE_FLAG_MASK );
     80 	size_t rp_comp_len = strlen ( rp_comp );
     81 	char buf[3];
     82 	char *buf_end;
     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 	for ( ; size ; size--, rp_comp += 2, bytes++ ) {
     95 		memcpy ( buf, rp_comp, 2 );
     96 		buf[2] = '\0';
     97 		*bytes = strtoul ( buf, &buf_end, 16 );
     98 		if ( buf_end != &buf[2] )
     99 			return -EINVAL_BYTE_STRING;
    100 	}
    101 	return 0;
    102 }
    103 
    104 /**
    105  * Parse IB SRP root path integer value
    106  *
    107  * @v rp_comp		Root path component string
    108  * @v default_value	Default value to use if component string is empty
    109  * @ret value		Value
    110  */
    111 static int ib_srp_parse_integer ( const char *rp_comp, int default_value ) {
    112 	int value;
    113 	char *end;
    114 
    115 	value = strtoul ( rp_comp, &end, 16 );
    116 	if ( *end )
    117 		return -EINVAL_INTEGER;
    118 
    119 	if ( end == rp_comp )
    120 		return default_value;
    121 
    122 	return value;
    123 }
    124 
    125 /**
    126  * Parse IB SRP root path literal component
    127  *
    128  * @v rp_comp		Root path component string
    129  * @v rp		IB SRP root path
    130  * @ret rc		Return status code
    131  */
    132 static int ib_srp_parse_literal ( const char *rp_comp __unused,
    133 				  struct ib_srp_root_path *rp __unused ) {
    134 	/* Ignore */
    135 	return 0;
    136 }
    137 
    138 /**
    139  * Parse IB SRP root path source GID
    140  *
    141  * @v rp_comp		Root path component string
    142  * @v rp		IB SRP root path
    143  * @ret rc		Return status code
    144  */
    145 static int ib_srp_parse_sgid ( const char *rp_comp,
    146 			       struct ib_srp_root_path *rp ) {
    147 	struct ib_device *ibdev;
    148 
    149 	/* Default to the GID of the last opened Infiniband device */
    150 	if ( ( ibdev = last_opened_ibdev() ) != NULL )
    151 		memcpy ( &rp->ib->sgid, &ibdev->gid, sizeof ( rp->ib->sgid ) );
    152 
    153 	return ib_srp_parse_byte_string ( rp_comp, rp->ib->sgid.u.bytes,
    154 					  ( sizeof ( rp->ib->sgid ) |
    155 					    IB_SRP_PARSE_OPTIONAL ) );
    156 }
    157 
    158 /**
    159  * Parse IB SRP root path initiator identifier extension
    160  *
    161  * @v rp_comp		Root path component string
    162  * @v rp		IB SRP root path
    163  * @ret rc		Return status code
    164  */
    165 static int ib_srp_parse_initiator_id_ext ( const char *rp_comp,
    166 					   struct ib_srp_root_path *rp ) {
    167 	struct ib_srp_initiator_port_id *port_id =
    168 		ib_srp_initiator_port_id ( rp->port_ids );
    169 
    170 	return ib_srp_parse_byte_string ( rp_comp, port_id->id_ext.u.bytes,
    171 					  ( sizeof ( port_id->id_ext ) |
    172 					    IB_SRP_PARSE_OPTIONAL ) );
    173 }
    174 
    175 /**
    176  * Parse IB SRP root path initiator HCA GUID
    177  *
    178  * @v rp_comp		Root path component string
    179  * @v rp		IB SRP root path
    180  * @ret rc		Return status code
    181  */
    182 static int ib_srp_parse_initiator_hca_guid ( const char *rp_comp,
    183 					     struct ib_srp_root_path *rp ) {
    184 	struct ib_srp_initiator_port_id *port_id =
    185 		ib_srp_initiator_port_id ( rp->port_ids );
    186 
    187 	/* Default to the GUID portion of the source GID */
    188 	memcpy ( &port_id->hca_guid, &rp->ib->sgid.u.half[1],
    189 		 sizeof ( port_id->hca_guid ) );
    190 
    191 	return ib_srp_parse_byte_string ( rp_comp, port_id->hca_guid.u.bytes,
    192 					  ( sizeof ( port_id->hca_guid ) |
    193 					    IB_SRP_PARSE_OPTIONAL ) );
    194 }
    195 
    196 /**
    197  * Parse IB SRP root path destination GID
    198  *
    199  * @v rp_comp		Root path component string
    200  * @v rp		IB SRP root path
    201  * @ret rc		Return status code
    202  */
    203 static int ib_srp_parse_dgid ( const char *rp_comp,
    204 			       struct ib_srp_root_path *rp ) {
    205 	return ib_srp_parse_byte_string ( rp_comp, rp->ib->dgid.u.bytes,
    206 					  ( sizeof ( rp->ib->dgid ) |
    207 					    IB_SRP_PARSE_REQUIRED ) );
    208 }
    209 
    210 /**
    211  * Parse IB SRP root path partition key
    212  *
    213  * @v rp_comp		Root path component string
    214  * @v rp		IB SRP root path
    215  * @ret rc		Return status code
    216  */
    217 static int ib_srp_parse_pkey ( const char *rp_comp,
    218 			       struct ib_srp_root_path *rp ) {
    219 	int pkey;
    220 
    221 	if ( ( pkey = ib_srp_parse_integer ( rp_comp, IB_PKEY_DEFAULT ) ) < 0 )
    222 		return pkey;
    223 	rp->ib->pkey = pkey;
    224 	return 0;
    225 }
    226 
    227 /**
    228  * Parse IB SRP root path service ID
    229  *
    230  * @v rp_comp		Root path component string
    231  * @v rp		IB SRP root path
    232  * @ret rc		Return status code
    233  */
    234 static int ib_srp_parse_service_id ( const char *rp_comp,
    235 				     struct ib_srp_root_path *rp ) {
    236 	return ib_srp_parse_byte_string ( rp_comp, rp->ib->service_id.u.bytes,
    237 					  ( sizeof ( rp->ib->service_id ) |
    238 					    IB_SRP_PARSE_REQUIRED ) );
    239 }
    240 
    241 /**
    242  * Parse IB SRP root path LUN
    243  *
    244  * @v rp_comp		Root path component string
    245  * @v rp		IB SRP root path
    246  * @ret rc		Return status code
    247  */
    248 static int ib_srp_parse_lun ( const char *rp_comp,
    249 			      struct ib_srp_root_path *rp ) {
    250 	return scsi_parse_lun ( rp_comp, rp->lun );
    251 }
    252 
    253 /**
    254  * Parse IB SRP root path target identifier extension
    255  *
    256  * @v rp_comp		Root path component string
    257  * @v rp		IB SRP root path
    258  * @ret rc		Return status code
    259  */
    260 static int ib_srp_parse_target_id_ext ( const char *rp_comp,
    261 					struct ib_srp_root_path *rp ) {
    262 	struct ib_srp_target_port_id *port_id =
    263 		ib_srp_target_port_id ( rp->port_ids );
    264 
    265 	return ib_srp_parse_byte_string ( rp_comp, port_id->id_ext.u.bytes,
    266 					  ( sizeof ( port_id->id_ext ) |
    267 					    IB_SRP_PARSE_REQUIRED ) );
    268 }
    269 
    270 /**
    271  * Parse IB SRP root path target I/O controller GUID
    272  *
    273  * @v rp_comp		Root path component string
    274  * @v rp		IB SRP root path
    275  * @ret rc		Return status code
    276  */
    277 static int ib_srp_parse_target_ioc_guid ( const char *rp_comp,
    278 					  struct ib_srp_root_path *rp ) {
    279 	struct ib_srp_target_port_id *port_id =
    280 		ib_srp_target_port_id ( rp->port_ids );
    281 
    282 	return ib_srp_parse_byte_string ( rp_comp, port_id->ioc_guid.u.bytes,
    283 					  ( sizeof ( port_id->ioc_guid ) |
    284 					    IB_SRP_PARSE_REQUIRED ) );
    285 }
    286 
    287 /** IB SRP root path component parser */
    288 struct ib_srp_root_path_parser {
    289 	/**
    290 	 * Parse IB SRP root path component
    291 	 *
    292 	 * @v rp_comp		Root path component string
    293 	 * @v rp		IB SRP root path
    294 	 * @ret rc		Return status code
    295 	 */
    296 	int ( * parse ) ( const char *rp_comp, struct ib_srp_root_path *rp );
    297 };
    298 
    299 /** IB SRP root path components */
    300 static struct ib_srp_root_path_parser ib_srp_rp_parser[] = {
    301 	{ ib_srp_parse_literal },
    302 	{ ib_srp_parse_sgid },
    303 	{ ib_srp_parse_initiator_id_ext },
    304 	{ ib_srp_parse_initiator_hca_guid },
    305 	{ ib_srp_parse_dgid },
    306 	{ ib_srp_parse_pkey },
    307 	{ ib_srp_parse_service_id },
    308 	{ ib_srp_parse_lun },
    309 	{ ib_srp_parse_target_id_ext },
    310 	{ ib_srp_parse_target_ioc_guid },
    311 };
    312 
    313 /** Number of IB SRP root path components */
    314 #define IB_SRP_NUM_RP_COMPONENTS \
    315 	( sizeof ( ib_srp_rp_parser ) / sizeof ( ib_srp_rp_parser[0] ) )
    316 
    317 /**
    318  * Parse IB SRP root path
    319  *
    320  * @v srp		SRP device
    321  * @v rp_string		Root path
    322  * @ret rc		Return status code
    323  */
    324 static int ib_srp_parse_root_path ( struct srp_device *srp,
    325 				    const char *rp_string ) {
    326 	struct ib_srp_parameters *ib_params = ib_srp_params ( srp );
    327 	struct ib_srp_root_path rp = {
    328 		.lun = &srp->lun,
    329 		.port_ids = &srp->port_ids,
    330 		.ib = ib_params,
    331 	};
    332 	char rp_string_copy[ strlen ( rp_string ) + 1 ];
    333 	char *rp_comp[IB_SRP_NUM_RP_COMPONENTS];
    334 	char *rp_string_tmp = rp_string_copy;
    335 	unsigned int i = 0;
    336 	int rc;
    337 
    338 	/* Split root path into component parts */
    339 	strcpy ( rp_string_copy, rp_string );
    340 	while ( 1 ) {
    341 		rp_comp[i++] = rp_string_tmp;
    342 		if ( i == IB_SRP_NUM_RP_COMPONENTS )
    343 			break;
    344 		for ( ; *rp_string_tmp != ':' ; rp_string_tmp++ ) {
    345 			if ( ! *rp_string_tmp ) {
    346 				DBGC ( srp, "SRP %p root path \"%s\" too "
    347 				       "short\n", srp, rp_string );
    348 				return -EINVAL_RP_TOO_SHORT;
    349 			}
    350 		}
    351 		*(rp_string_tmp++) = '\0';
    352 	}
    353 
    354 	/* Parse root path components */
    355 	for ( i = 0 ; i < IB_SRP_NUM_RP_COMPONENTS ; i++ ) {
    356 		if ( ( rc = ib_srp_rp_parser[i].parse ( rp_comp[i],
    357 							&rp ) ) != 0 ) {
    358 			DBGC ( srp, "SRP %p could not parse \"%s\" in root "
    359 			       "path \"%s\": %s\n", srp, rp_comp[i],
    360 			       rp_string, strerror ( rc ) );
    361 			return rc;
    362 		}
    363 	}
    364 
    365 	return 0;
    366 }
    367 
    368 /**
    369  * Connect IB SRP session
    370  *
    371  * @v srp		SRP device
    372  * @ret rc		Return status code
    373  */
    374 static int ib_srp_connect ( struct srp_device *srp ) {
    375 	struct ib_srp_parameters *ib_params = ib_srp_params ( srp );
    376 	struct ib_device *ibdev;
    377 	int rc;
    378 
    379 	/* Identify Infiniband device */
    380 	ibdev = find_ibdev ( &ib_params->sgid );
    381 	if ( ! ibdev ) {
    382 		DBGC ( srp, "SRP %p could not identify Infiniband device\n",
    383 		       srp );
    384 		return -ENODEV;
    385 	}
    386 
    387 	/* Configure remaining SRP parameters */
    388 	srp->memory_handle = ibdev->rdma_key;
    389 
    390 	/* Open CMRC socket */
    391 	if ( ( rc = ib_cmrc_open ( &srp->socket, ibdev, &ib_params->dgid,
    392 				   &ib_params->service_id ) ) != 0 ) {
    393 		DBGC ( srp, "SRP %p could not open CMRC socket: %s\n",
    394 		       srp, strerror ( rc ) );
    395 		return rc;
    396 	}
    397 
    398 	return 0;
    399 }
    400 
    401 /** IB SRP transport type */
    402 struct srp_transport_type ib_srp_transport = {
    403 	.priv_len = sizeof ( struct ib_srp_parameters ),
    404 	.parse_root_path = ib_srp_parse_root_path,
    405 	.connect = ib_srp_connect,
    406 };
    407