aboutsummaryrefslogtreecommitdiffstats
path: root/gpxe/src/net/infiniband/ib_srp.c
diff options
context:
space:
mode:
Diffstat (limited to 'gpxe/src/net/infiniband/ib_srp.c')
-rw-r--r--gpxe/src/net/infiniband/ib_srp.c406
1 files changed, 406 insertions, 0 deletions
diff --git a/gpxe/src/net/infiniband/ib_srp.c b/gpxe/src/net/infiniband/ib_srp.c
new file mode 100644
index 00000000..c156d3ae
--- /dev/null
+++ b/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,
+};