diff options
Diffstat (limited to 'contrib/syslinux/syslinux-4.03/gpxe/src/net/infiniband/ib_srp.c')
-rw-r--r-- | contrib/syslinux/syslinux-4.03/gpxe/src/net/infiniband/ib_srp.c | 406 |
1 files changed, 406 insertions, 0 deletions
diff --git a/contrib/syslinux/syslinux-4.03/gpxe/src/net/infiniband/ib_srp.c b/contrib/syslinux/syslinux-4.03/gpxe/src/net/infiniband/ib_srp.c new file mode 100644 index 0000000..c156d3a --- /dev/null +++ b/contrib/syslinux/syslinux-4.03/gpxe/src/net/infiniband/ib_srp.c @@ -0,0 +1,406 @@ +/* + * Copyright (C) 2009 Fen Systems Ltd <mbrown@fensystems.co.uk>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +FILE_LICENCE ( BSD2 ); + +#include <stdlib.h> +#include <errno.h> +#include <gpxe/srp.h> +#include <gpxe/infiniband.h> +#include <gpxe/ib_cmrc.h> +#include <gpxe/ib_srp.h> + +/** + * @file + * + * SCSI RDMA Protocol over Infiniband + * + */ + +/* Disambiguate the various possible EINVALs */ +#define EINVAL_BYTE_STRING_LEN ( EINVAL | EUNIQ_01 ) +#define EINVAL_BYTE_STRING ( EINVAL | EUNIQ_02 ) +#define EINVAL_INTEGER ( EINVAL | EUNIQ_03 ) +#define EINVAL_RP_TOO_SHORT ( EINVAL | EUNIQ_04 ) + +/** IB SRP parse flags */ +enum ib_srp_parse_flags { + IB_SRP_PARSE_REQUIRED = 0x0000, + IB_SRP_PARSE_OPTIONAL = 0x8000, + IB_SRP_PARSE_FLAG_MASK = 0xf000, +}; + +/** IB SRP root path parameters */ +struct ib_srp_root_path { + /** SCSI LUN */ + struct scsi_lun *lun; + /** SRP port IDs */ + struct srp_port_ids *port_ids; + /** IB SRP parameters */ + struct ib_srp_parameters *ib; +}; + +/** + * Parse IB SRP root path byte-string value + * + * @v rp_comp Root path component string + * @v default_value Default value to use if component string is empty + * @ret value Value + */ +static int ib_srp_parse_byte_string ( const char *rp_comp, uint8_t *bytes, + unsigned int size_flags ) { + size_t size = ( size_flags & ~IB_SRP_PARSE_FLAG_MASK ); + size_t rp_comp_len = strlen ( rp_comp ); + char buf[3]; + char *buf_end; + + /* Allow optional components to be empty */ + if ( ( rp_comp_len == 0 ) && + ( size_flags & IB_SRP_PARSE_OPTIONAL ) ) + return 0; + + /* Check string length */ + if ( rp_comp_len != ( 2 * size ) ) + return -EINVAL_BYTE_STRING_LEN; + + /* Parse byte string */ + for ( ; size ; size--, rp_comp += 2, bytes++ ) { + memcpy ( buf, rp_comp, 2 ); + buf[2] = '\0'; + *bytes = strtoul ( buf, &buf_end, 16 ); + if ( buf_end != &buf[2] ) + return -EINVAL_BYTE_STRING; + } + return 0; +} + +/** + * Parse IB SRP root path integer value + * + * @v rp_comp Root path component string + * @v default_value Default value to use if component string is empty + * @ret value Value + */ +static int ib_srp_parse_integer ( const char *rp_comp, int default_value ) { + int value; + char *end; + + value = strtoul ( rp_comp, &end, 16 ); + if ( *end ) + return -EINVAL_INTEGER; + + if ( end == rp_comp ) + return default_value; + + return value; +} + +/** + * Parse IB SRP root path literal component + * + * @v rp_comp Root path component string + * @v rp IB SRP root path + * @ret rc Return status code + */ +static int ib_srp_parse_literal ( const char *rp_comp __unused, + struct ib_srp_root_path *rp __unused ) { + /* Ignore */ + return 0; +} + +/** + * Parse IB SRP root path source GID + * + * @v rp_comp Root path component string + * @v rp IB SRP root path + * @ret rc Return status code + */ +static int ib_srp_parse_sgid ( const char *rp_comp, + struct ib_srp_root_path *rp ) { + struct ib_device *ibdev; + + /* Default to the GID of the last opened Infiniband device */ + if ( ( ibdev = last_opened_ibdev() ) != NULL ) + memcpy ( &rp->ib->sgid, &ibdev->gid, sizeof ( rp->ib->sgid ) ); + + return ib_srp_parse_byte_string ( rp_comp, rp->ib->sgid.u.bytes, + ( sizeof ( rp->ib->sgid ) | + IB_SRP_PARSE_OPTIONAL ) ); +} + +/** + * Parse IB SRP root path initiator identifier extension + * + * @v rp_comp Root path component string + * @v rp IB SRP root path + * @ret rc Return status code + */ +static int ib_srp_parse_initiator_id_ext ( const char *rp_comp, + struct ib_srp_root_path *rp ) { + struct ib_srp_initiator_port_id *port_id = + ib_srp_initiator_port_id ( rp->port_ids ); + + return ib_srp_parse_byte_string ( rp_comp, port_id->id_ext.u.bytes, + ( sizeof ( port_id->id_ext ) | + IB_SRP_PARSE_OPTIONAL ) ); +} + +/** + * Parse IB SRP root path initiator HCA GUID + * + * @v rp_comp Root path component string + * @v rp IB SRP root path + * @ret rc Return status code + */ +static int ib_srp_parse_initiator_hca_guid ( const char *rp_comp, + struct ib_srp_root_path *rp ) { + struct ib_srp_initiator_port_id *port_id = + ib_srp_initiator_port_id ( rp->port_ids ); + + /* Default to the GUID portion of the source GID */ + memcpy ( &port_id->hca_guid, &rp->ib->sgid.u.half[1], + sizeof ( port_id->hca_guid ) ); + + return ib_srp_parse_byte_string ( rp_comp, port_id->hca_guid.u.bytes, + ( sizeof ( port_id->hca_guid ) | + IB_SRP_PARSE_OPTIONAL ) ); +} + +/** + * Parse IB SRP root path destination GID + * + * @v rp_comp Root path component string + * @v rp IB SRP root path + * @ret rc Return status code + */ +static int ib_srp_parse_dgid ( const char *rp_comp, + struct ib_srp_root_path *rp ) { + return ib_srp_parse_byte_string ( rp_comp, rp->ib->dgid.u.bytes, + ( sizeof ( rp->ib->dgid ) | + IB_SRP_PARSE_REQUIRED ) ); +} + +/** + * Parse IB SRP root path partition key + * + * @v rp_comp Root path component string + * @v rp IB SRP root path + * @ret rc Return status code + */ +static int ib_srp_parse_pkey ( const char *rp_comp, + struct ib_srp_root_path *rp ) { + int pkey; + + if ( ( pkey = ib_srp_parse_integer ( rp_comp, IB_PKEY_DEFAULT ) ) < 0 ) + return pkey; + rp->ib->pkey = pkey; + return 0; +} + +/** + * Parse IB SRP root path service ID + * + * @v rp_comp Root path component string + * @v rp IB SRP root path + * @ret rc Return status code + */ +static int ib_srp_parse_service_id ( const char *rp_comp, + struct ib_srp_root_path *rp ) { + return ib_srp_parse_byte_string ( rp_comp, rp->ib->service_id.u.bytes, + ( sizeof ( rp->ib->service_id ) | + IB_SRP_PARSE_REQUIRED ) ); +} + +/** + * Parse IB SRP root path LUN + * + * @v rp_comp Root path component string + * @v rp IB SRP root path + * @ret rc Return status code + */ +static int ib_srp_parse_lun ( const char *rp_comp, + struct ib_srp_root_path *rp ) { + return scsi_parse_lun ( rp_comp, rp->lun ); +} + +/** + * Parse IB SRP root path target identifier extension + * + * @v rp_comp Root path component string + * @v rp IB SRP root path + * @ret rc Return status code + */ +static int ib_srp_parse_target_id_ext ( const char *rp_comp, + struct ib_srp_root_path *rp ) { + struct ib_srp_target_port_id *port_id = + ib_srp_target_port_id ( rp->port_ids ); + + return ib_srp_parse_byte_string ( rp_comp, port_id->id_ext.u.bytes, + ( sizeof ( port_id->id_ext ) | + IB_SRP_PARSE_REQUIRED ) ); +} + +/** + * Parse IB SRP root path target I/O controller GUID + * + * @v rp_comp Root path component string + * @v rp IB SRP root path + * @ret rc Return status code + */ +static int ib_srp_parse_target_ioc_guid ( const char *rp_comp, + struct ib_srp_root_path *rp ) { + struct ib_srp_target_port_id *port_id = + ib_srp_target_port_id ( rp->port_ids ); + + return ib_srp_parse_byte_string ( rp_comp, port_id->ioc_guid.u.bytes, + ( sizeof ( port_id->ioc_guid ) | + IB_SRP_PARSE_REQUIRED ) ); +} + +/** IB SRP root path component parser */ +struct ib_srp_root_path_parser { + /** + * Parse IB SRP root path component + * + * @v rp_comp Root path component string + * @v rp IB SRP root path + * @ret rc Return status code + */ + int ( * parse ) ( const char *rp_comp, struct ib_srp_root_path *rp ); +}; + +/** IB SRP root path components */ +static struct ib_srp_root_path_parser ib_srp_rp_parser[] = { + { ib_srp_parse_literal }, + { ib_srp_parse_sgid }, + { ib_srp_parse_initiator_id_ext }, + { ib_srp_parse_initiator_hca_guid }, + { ib_srp_parse_dgid }, + { ib_srp_parse_pkey }, + { ib_srp_parse_service_id }, + { ib_srp_parse_lun }, + { ib_srp_parse_target_id_ext }, + { ib_srp_parse_target_ioc_guid }, +}; + +/** Number of IB SRP root path components */ +#define IB_SRP_NUM_RP_COMPONENTS \ + ( sizeof ( ib_srp_rp_parser ) / sizeof ( ib_srp_rp_parser[0] ) ) + +/** + * Parse IB SRP root path + * + * @v srp SRP device + * @v rp_string Root path + * @ret rc Return status code + */ +static int ib_srp_parse_root_path ( struct srp_device *srp, + const char *rp_string ) { + struct ib_srp_parameters *ib_params = ib_srp_params ( srp ); + struct ib_srp_root_path rp = { + .lun = &srp->lun, + .port_ids = &srp->port_ids, + .ib = ib_params, + }; + char rp_string_copy[ strlen ( rp_string ) + 1 ]; + char *rp_comp[IB_SRP_NUM_RP_COMPONENTS]; + char *rp_string_tmp = rp_string_copy; + unsigned int i = 0; + int rc; + + /* Split root path into component parts */ + strcpy ( rp_string_copy, rp_string ); + while ( 1 ) { + rp_comp[i++] = rp_string_tmp; + if ( i == IB_SRP_NUM_RP_COMPONENTS ) + break; + for ( ; *rp_string_tmp != ':' ; rp_string_tmp++ ) { + if ( ! *rp_string_tmp ) { + DBGC ( srp, "SRP %p root path \"%s\" too " + "short\n", srp, rp_string ); + return -EINVAL_RP_TOO_SHORT; + } + } + *(rp_string_tmp++) = '\0'; + } + + /* Parse root path components */ + for ( i = 0 ; i < IB_SRP_NUM_RP_COMPONENTS ; i++ ) { + if ( ( rc = ib_srp_rp_parser[i].parse ( rp_comp[i], + &rp ) ) != 0 ) { + DBGC ( srp, "SRP %p could not parse \"%s\" in root " + "path \"%s\": %s\n", srp, rp_comp[i], + rp_string, strerror ( rc ) ); + return rc; + } + } + + return 0; +} + +/** + * Connect IB SRP session + * + * @v srp SRP device + * @ret rc Return status code + */ +static int ib_srp_connect ( struct srp_device *srp ) { + struct ib_srp_parameters *ib_params = ib_srp_params ( srp ); + struct ib_device *ibdev; + int rc; + + /* Identify Infiniband device */ + ibdev = find_ibdev ( &ib_params->sgid ); + if ( ! ibdev ) { + DBGC ( srp, "SRP %p could not identify Infiniband device\n", + srp ); + return -ENODEV; + } + + /* Configure remaining SRP parameters */ + srp->memory_handle = ibdev->rdma_key; + + /* Open CMRC socket */ + if ( ( rc = ib_cmrc_open ( &srp->socket, ibdev, &ib_params->dgid, + &ib_params->service_id ) ) != 0 ) { + DBGC ( srp, "SRP %p could not open CMRC socket: %s\n", + srp, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** IB SRP transport type */ +struct srp_transport_type ib_srp_transport = { + .priv_len = sizeof ( struct ib_srp_parameters ), + .parse_root_path = ib_srp_parse_root_path, + .connect = ib_srp_connect, +}; |