123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581 |
- /*
- * 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/interface.h>
- #include <ipxe/uri.h>
- #include <ipxe/open.h>
- #include <ipxe/base16.h>
- #include <ipxe/acpi.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 __einfo_error ( EINFO_EINVAL_BYTE_STRING_LEN )
- #define EINFO_EINVAL_BYTE_STRING_LEN __einfo_uniqify \
- ( EINFO_EINVAL, 0x01, "Invalid byte string length" )
- #define EINVAL_INTEGER __einfo_error ( EINFO_EINVAL_INTEGER )
- #define EINFO_EINVAL_INTEGER __einfo_uniqify \
- ( EINFO_EINVAL, 0x03, "Invalid integer" )
- #define EINVAL_RP_TOO_SHORT __einfo_error ( EINFO_EINVAL_RP_TOO_SHORT )
- #define EINFO_EINVAL_RP_TOO_SHORT __einfo_uniqify \
- ( EINFO_EINVAL, 0x04, "Root path too short" )
-
- /******************************************************************************
- *
- * IB SRP devices
- *
- ******************************************************************************
- */
-
- /** An Infiniband SRP device */
- struct ib_srp_device {
- /** Reference count */
- struct refcnt refcnt;
-
- /** SRP transport interface */
- struct interface srp;
- /** CMRC interface */
- struct interface cmrc;
-
- /** Infiniband device */
- struct ib_device *ibdev;
-
- /** Destination GID (for boot firmware table) */
- union ib_gid dgid;
- /** Service ID (for boot firmware table) */
- union ib_guid service_id;
- };
-
- /**
- * Free IB SRP device
- *
- * @v refcnt Reference count
- */
- static void ib_srp_free ( struct refcnt *refcnt ) {
- struct ib_srp_device *ib_srp =
- container_of ( refcnt, struct ib_srp_device, refcnt );
-
- ibdev_put ( ib_srp->ibdev );
- free ( ib_srp );
- }
-
- /**
- * Close IB SRP device
- *
- * @v ib_srp IB SRP device
- * @v rc Reason for close
- */
- static void ib_srp_close ( struct ib_srp_device *ib_srp, int rc ) {
-
- /* Shut down interfaces */
- intf_shutdown ( &ib_srp->cmrc, rc );
- intf_shutdown ( &ib_srp->srp, rc );
- }
-
- /**
- * Describe IB SRP device in an ACPI table
- *
- * @v srpdev SRP device
- * @v acpi ACPI table
- * @v len Length of ACPI table
- * @ret rc Return status code
- */
- static int ib_srp_describe ( struct ib_srp_device *ib_srp,
- struct acpi_description_header *acpi,
- size_t len ) {
- struct ib_device *ibdev = ib_srp->ibdev;
- struct sbft_table *sbft =
- container_of ( acpi, struct sbft_table, acpi );
- struct sbft_ib_subtable *ib_sbft;
- size_t used;
-
- /* Sanity check */
- if ( acpi->signature != SBFT_SIG )
- return -EINVAL;
-
- /* Append IB subtable to existing table */
- used = le32_to_cpu ( sbft->acpi.length );
- sbft->ib_offset = cpu_to_le16 ( used );
- ib_sbft = ( ( ( void * ) sbft ) + used );
- used += sizeof ( *ib_sbft );
- if ( used > len )
- return -ENOBUFS;
- sbft->acpi.length = cpu_to_le32 ( used );
-
- /* Populate subtable */
- memcpy ( &ib_sbft->sgid, &ibdev->gid, sizeof ( ib_sbft->sgid ) );
- memcpy ( &ib_sbft->dgid, &ib_srp->dgid, sizeof ( ib_sbft->dgid ) );
- memcpy ( &ib_sbft->service_id, &ib_srp->service_id,
- sizeof ( ib_sbft->service_id ) );
- ib_sbft->pkey = cpu_to_le16 ( ibdev->pkey );
-
- return 0;
- }
-
- /** IB SRP CMRC interface operations */
- static struct interface_operation ib_srp_cmrc_op[] = {
- INTF_OP ( intf_close, struct ib_srp_device *, ib_srp_close ),
- };
-
- /** IB SRP CMRC interface descriptor */
- static struct interface_descriptor ib_srp_cmrc_desc =
- INTF_DESC_PASSTHRU ( struct ib_srp_device, cmrc, ib_srp_cmrc_op, srp );
-
- /** IB SRP SRP interface operations */
- static struct interface_operation ib_srp_srp_op[] = {
- INTF_OP ( acpi_describe, struct ib_srp_device *, ib_srp_describe ),
- INTF_OP ( intf_close, struct ib_srp_device *, ib_srp_close ),
- };
-
- /** IB SRP SRP interface descriptor */
- static struct interface_descriptor ib_srp_srp_desc =
- INTF_DESC_PASSTHRU ( struct ib_srp_device, srp, ib_srp_srp_op, cmrc );
-
- /**
- * Open IB SRP device
- *
- * @v block Block control interface
- * @v ibdev Infiniband device
- * @v dgid Destination GID
- * @v service_id Service ID
- * @v initiator Initiator port ID
- * @v target Target port ID
- * @v lun SCSI LUN
- * @ret rc Return status code
- */
- static int ib_srp_open ( struct interface *block, struct ib_device *ibdev,
- union ib_gid *dgid, union ib_guid *service_id,
- union srp_port_id *initiator,
- union srp_port_id *target, struct scsi_lun *lun ) {
- struct ib_srp_device *ib_srp;
- int rc;
-
- /* Allocate and initialise structure */
- ib_srp = zalloc ( sizeof ( *ib_srp ) );
- if ( ! ib_srp ) {
- rc = -ENOMEM;
- goto err_zalloc;
- }
- ref_init ( &ib_srp->refcnt, ib_srp_free );
- intf_init ( &ib_srp->srp, &ib_srp_srp_desc, &ib_srp->refcnt );
- intf_init ( &ib_srp->cmrc, &ib_srp_cmrc_desc, &ib_srp->refcnt );
- ib_srp->ibdev = ibdev_get ( ibdev );
- DBGC ( ib_srp, "IBSRP %p for " IB_GID_FMT " " IB_GUID_FMT "\n",
- ib_srp, IB_GID_ARGS ( dgid ), IB_GUID_ARGS ( service_id ) );
-
- /* Preserve parameters required for boot firmware table */
- memcpy ( &ib_srp->dgid, dgid, sizeof ( ib_srp->dgid ) );
- memcpy ( &ib_srp->service_id, service_id,
- sizeof ( ib_srp->service_id ) );
-
- /* Open CMRC socket */
- if ( ( rc = ib_cmrc_open ( &ib_srp->cmrc, ibdev, dgid,
- service_id, "SRP" ) ) != 0 ) {
- DBGC ( ib_srp, "IBSRP %p could not open CMRC socket: %s\n",
- ib_srp, strerror ( rc ) );
- goto err_cmrc_open;
- }
-
- /* Attach SRP device to parent interface */
- if ( ( rc = srp_open ( block, &ib_srp->srp, initiator, target,
- ibdev->rdma_key, lun ) ) != 0 ) {
- DBGC ( ib_srp, "IBSRP %p could not create SRP device: %s\n",
- ib_srp, strerror ( rc ) );
- goto err_srp_open;
- }
-
- /* Mortalise self and return */
- ref_put ( &ib_srp->refcnt );
- return 0;
-
- err_srp_open:
- err_cmrc_open:
- ib_srp_close ( ib_srp, rc );
- ref_put ( &ib_srp->refcnt );
- err_zalloc:
- return rc;
- }
-
- /******************************************************************************
- *
- * IB SRP URIs
- *
- ******************************************************************************
- */
-
- /** 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 {
- /** Source GID */
- union ib_gid sgid;
- /** Initiator port ID */
- union ib_srp_initiator_port_id initiator;
- /** Destination GID */
- union ib_gid dgid;
- /** Partition key */
- uint16_t pkey;
- /** Service ID */
- union ib_guid service_id;
- /** SCSI LUN */
- struct scsi_lun lun;
- /** Target port ID */
- union ib_srp_target_port_id target;
- };
-
- /**
- * 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, size );
- if ( decoded_size < 0 )
- return decoded_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 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->sgid, &ibdev->gid, sizeof ( rp->sgid ) );
-
- return ib_srp_parse_byte_string ( rp_comp, rp->sgid.bytes,
- ( sizeof ( rp->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 ) {
- union ib_srp_initiator_port_id *port_id = &rp->initiator;
-
- return ib_srp_parse_byte_string ( rp_comp, port_id->ib.id_ext.bytes,
- ( sizeof ( port_id->ib.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 ) {
- union ib_srp_initiator_port_id *port_id = &rp->initiator;
-
- /* Default to the GUID portion of the source GID */
- memcpy ( &port_id->ib.hca_guid, &rp->sgid.s.guid,
- sizeof ( port_id->ib.hca_guid ) );
-
- return ib_srp_parse_byte_string ( rp_comp, port_id->ib.hca_guid.bytes,
- ( sizeof ( port_id->ib.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->dgid.bytes,
- ( sizeof ( rp->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->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->service_id.bytes,
- ( sizeof ( rp->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 ) {
- union ib_srp_target_port_id *port_id = &rp->target;
-
- return ib_srp_parse_byte_string ( rp_comp, port_id->ib.id_ext.bytes,
- ( sizeof ( port_id->ib.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 ) {
- union ib_srp_target_port_id *port_id = &rp->target;
-
- return ib_srp_parse_byte_string ( rp_comp, port_id->ib.ioc_guid.bytes,
- ( sizeof ( port_id->ib.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_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 rp_string Root path string
- * @v rp IB SRP root path
- * @ret rc Return status code
- */
- static int ib_srp_parse_root_path ( const char *rp_string,
- struct ib_srp_root_path *rp ) {
- struct ib_srp_root_path_parser *parser;
- 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 ) {
- DBG ( "IBSRP root path \"%s\" too short\n",
- 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++ ) {
- parser = &ib_srp_rp_parser[i];
- if ( ( rc = parser->parse ( rp_comp[i], rp ) ) != 0 ) {
- DBG ( "IBSRP could not parse \"%s\" in root path "
- "\"%s\": %s\n", rp_comp[i], rp_string,
- strerror ( rc ) );
- return rc;
- }
- }
-
- return 0;
- }
-
- /**
- * Open IB SRP URI
- *
- * @v parent Parent interface
- * @v uri URI
- * @ret rc Return status code
- */
- static int ib_srp_open_uri ( struct interface *parent, struct uri *uri ) {
- struct ib_srp_root_path rp;
- struct ib_device *ibdev;
- int rc;
-
- /* Parse URI */
- if ( ! uri->opaque )
- return -EINVAL;
- memset ( &rp, 0, sizeof ( rp ) );
- if ( ( rc = ib_srp_parse_root_path ( uri->opaque, &rp ) ) != 0 )
- return rc;
-
- /* Identify Infiniband device */
- ibdev = find_ibdev ( &rp.sgid );
- if ( ! ibdev ) {
- DBG ( "IBSRP could not identify Infiniband device\n" );
- return -ENODEV;
- }
-
- /* Open IB SRP device */
- if ( ( rc = ib_srp_open ( parent, ibdev, &rp.dgid, &rp.service_id,
- &rp.initiator.srp, &rp.target.srp,
- &rp.lun ) ) != 0 )
- return rc;
-
- return 0;
- }
-
- /** IB SRP URI opener */
- struct uri_opener ib_srp_uri_opener __uri_opener = {
- .scheme = "ib_srp",
- .open = ib_srp_open_uri,
- };
|