mirror of https://github.com/ipxe/ipxe.git
405 lines
11 KiB
C
405 lines
11 KiB
C
/*
|
|
* 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 <ipxe/base16.h>
|
|
#include <ipxe/srp.h>
|
|
#include <ipxe/infiniband.h>
|
|
#include <ipxe/ib_cmrc.h>
|
|
#include <ipxe/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 );
|
|
int decoded_size;
|
|
|
|
/* 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 */
|
|
decoded_size = base16_decode ( rp_comp, bytes );
|
|
if ( decoded_size < 0 )
|
|
return decoded_size;
|
|
assert ( decoded_size == size );
|
|
|
|
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,
|
|
};
|