iPXE
Data Structures | Defines | Functions | Variables
srp.c File Reference

SCSI RDMA Protocol. More...

#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ipxe/scsi.h>
#include <ipxe/xfer.h>
#include <ipxe/features.h>
#include <ipxe/srp.h>

Go to the source code of this file.

Data Structures

struct  srp_device
 An SRP device. More...
struct  srp_command
 An SRP command. More...

Defines

#define SRP_MAX_I_T_IU_LEN   80
 Maximum length of any initiator-to-target IU that we will send.
#define EINFO_SRP_LOGIN_REJ(reason, desc)   __einfo_uniqify ( EINFO_EPERM, ( (reason) & 0x0f ), desc )
#define EPERM_UNKNOWN   __einfo_error ( EINFO_EPERM_UNKNOWN )
#define EINFO_EPERM_UNKNOWN
#define EPERM_INSUFFICIENT_RESOURCES   __einfo_error ( EINFO_EPERM_INSUFFICIENT_RESOURCES )
#define EINFO_EPERM_INSUFFICIENT_RESOURCES
#define EPERM_BAD_MAX_I_T_IU_LEN   __einfo_error ( EINFO_EPERM_BAD_MAX_I_T_IU_LEN )
#define EINFO_EPERM_BAD_MAX_I_T_IU_LEN
#define EPERM_CANNOT_ASSOCIATE   __einfo_error ( EINFO_EPERM_CANNOT_ASSOCIATE )
#define EINFO_EPERM_CANNOT_ASSOCIATE
#define EPERM_UNSUPPORTED_BUFFER_FORMAT   __einfo_error ( EINFO_EPERM_UNSUPPORTED_BUFFER_FORMAT )
#define EINFO_EPERM_UNSUPPORTED_BUFFER_FORMAT
#define EPERM_NO_MULTIPLE_CHANNELS   __einfo_error ( EINFO_EPERM_NO_MULTIPLE_CHANNELS )
#define EINFO_EPERM_NO_MULTIPLE_CHANNELS
#define EPERM_NO_MORE_CHANNELS   __einfo_error ( EINFO_EPERM_NO_MORE_CHANNELS )
#define EINFO_EPERM_NO_MORE_CHANNELS
#define EPERM_LOGIN_REJ(reason_nibble)

Functions

 FILE_LICENCE (BSD2)
 FEATURE (FEATURE_PROTOCOL,"SRP", DHCP_EB_FEATURE_SRP, 1)
static struct srp_devicesrpdev_get (struct srp_device *srpdev)
 Get reference to SRP device.
static void srpdev_put (struct srp_device *srpdev)
 Drop reference to SRP device.
static struct srp_commandsrpcmd_get (struct srp_command *srpcmd)
 Get reference to SRP command.
static void srpcmd_put (struct srp_command *srpcmd)
 Drop reference to SRP command.
static void srpcmd_free (struct refcnt *refcnt)
 Free SRP command.
static void srpcmd_close (struct srp_command *srpcmd, int rc)
 Close SRP command.
static void srpdev_close (struct srp_device *srpdev, int rc)
 Close SRP device.
static struct srp_commandsrp_find_tag (struct srp_device *srpdev, uint32_t tag)
 Identify SRP command by tag.
static int srp_new_tag (struct srp_device *srpdev)
 Choose an SRP command tag.
static int srp_login (struct srp_device *srpdev, union srp_port_id *initiator, union srp_port_id *target, uint32_t tag)
 Transmit SRP login request.
static int srp_login_rsp (struct srp_device *srpdev, const void *data, size_t len)
 Receive SRP login response.
static int srp_login_rej (struct srp_device *srpdev, const void *data, size_t len)
 Receive SRP login rejection.
static int srp_cmd (struct srp_device *srpdev, struct scsi_cmd *command, uint32_t tag)
 Transmit SRP SCSI command.
static int srp_rsp (struct srp_device *srpdev, const void *data, size_t len)
 Receive SRP SCSI response.
static int srp_unrecognised (struct srp_device *srpdev, const void *data, size_t len)
 Receive SRP unrecognised response IU.
static int srpdev_scsi_command (struct srp_device *srpdev, struct interface *parent, struct scsi_cmd *command)
 Issue SRP SCSI command.
static int srpdev_deliver (struct srp_device *srpdev, struct io_buffer *iobuf, struct xfer_metadata *meta __unused)
 Receive data from SRP socket.
static size_t srpdev_window (struct srp_device *srpdev)
 Check SRP device flow-control window.
int srp_open (struct interface *block, struct interface *socket, union srp_port_id *initiator, union srp_port_id *target, uint32_t memory_handle, struct scsi_lun *lun)
 Open SRP device.

Variables

static struct interface_operation srpcmd_scsi_op []
 SRP command SCSI interface operations.
static struct interface_descriptor srpcmd_scsi_desc
 SRP command SCSI interface descriptor.
static struct interface_operation srpdev_socket_op []
 SRP device socket interface operations.
static struct interface_descriptor srpdev_socket_desc
 SRP device socket interface descriptor.
static struct interface_operation srpdev_scsi_op []
 SRP device SCSI interface operations.
static struct interface_descriptor srpdev_scsi_desc
 SRP device SCSI interface descriptor.

Detailed Description

SCSI RDMA Protocol.

Definition in file srp.c.


Define Documentation

#define SRP_MAX_I_T_IU_LEN   80

Maximum length of any initiator-to-target IU that we will send.

The longest IU is a SRP_CMD with no additional CDB and two direct data buffer descriptors, which comes to 80 bytes.

Definition at line 55 of file srp.c.

Referenced by srp_cmd(), and srp_login().

#define EINFO_SRP_LOGIN_REJ (   reason,
  desc 
)    __einfo_uniqify ( EINFO_EPERM, ( (reason) & 0x0f ), desc )

Definition at line 58 of file srp.c.

Definition at line 60 of file srp.c.

Value:
EINFO_SRP_LOGIN_REJ (                         \
        SRP_LOGIN_REJ_REASON_UNKNOWN,                                         \
        "Unable to establish RDMA channel, no reason specified" )

Definition at line 62 of file srp.c.

Definition at line 65 of file srp.c.

Value:
EINFO_SRP_LOGIN_REJ (         \
        SRP_LOGIN_REJ_REASON_INSUFFICIENT_RESOURCES,                          \
        "Insufficient RDMA channel resources" )

Definition at line 67 of file srp.c.

Definition at line 70 of file srp.c.

Value:
EINFO_SRP_LOGIN_REJ (                 \
        SRP_LOGIN_REJ_REASON_BAD_MAX_I_T_IU_LEN,                              \
        "Requested maximum initiator to target IU length value too large" )

Definition at line 72 of file srp.c.

Definition at line 75 of file srp.c.

Value:
EINFO_SRP_LOGIN_REJ (                 \
        SRP_LOGIN_REJ_REASON_CANNOT_ASSOCIATE,                                \
        "Unable to associate RDMA channel with specified I_T nexus" )

Definition at line 77 of file srp.c.

Definition at line 80 of file srp.c.

Value:
EINFO_SRP_LOGIN_REJ (         \
        SRP_LOGIN_REJ_REASON_UNSUPPORTED_BUFFER_FORMAT,                       \
        "One or more requested data buffer descriptor formats not supported" )

Definition at line 82 of file srp.c.

Definition at line 85 of file srp.c.

Value:
EINFO_SRP_LOGIN_REJ (                 \
        SRP_LOGIN_REJ_REASON_NO_MULTIPLE_CHANNELS,                            \
        "SRP target does not support multiple RDMA channels per I_T nexus" )

Definition at line 87 of file srp.c.

Definition at line 90 of file srp.c.

Value:
EINFO_SRP_LOGIN_REJ (                 \
        SRP_LOGIN_REJ_REASON_NO_MORE_CHANNELS,                                \
        "RDMA channel limit reached for this initiator" )

Definition at line 92 of file srp.c.

#define EPERM_LOGIN_REJ (   reason_nibble)

Function Documentation

FILE_LICENCE ( BSD2  )
FEATURE ( FEATURE_PROTOCOL  ,
"SRP"  ,
DHCP_EB_FEATURE_SRP  ,
 
)
static struct srp_device* srpdev_get ( struct srp_device srpdev) [static, read]

Get reference to SRP device.

Parameters:
srpdevSRP device
Return values:
srpdevSRP device

Definition at line 142 of file srp.c.

References ref_get.

Referenced by srpdev_scsi_command().

                                         {
        ref_get ( &srpdev->refcnt );
        return srpdev;
}
static void srpdev_put ( struct srp_device srpdev) [inline, static]

Drop reference to SRP device.

Parameters:
srpdevSRP device

Definition at line 153 of file srp.c.

References ref_put.

Referenced by srpcmd_free().

                                         {
        ref_put ( &srpdev->refcnt );
}
static struct srp_command* srpcmd_get ( struct srp_command srpcmd) [static, read]

Get reference to SRP command.

Parameters:
srpcmdSRP command
Return values:
srpcmdSRP command

Definition at line 164 of file srp.c.

References ref_get.

Referenced by srp_rsp(), and srpdev_close().

                                          {
        ref_get ( &srpcmd->refcnt );
        return srpcmd;
}
static void srpcmd_put ( struct srp_command srpcmd) [inline, static]

Drop reference to SRP command.

Parameters:
srpcmdSRP command

Definition at line 175 of file srp.c.

References ref_put.

Referenced by srp_rsp(), srpcmd_close(), and srpdev_close().

                                          {
        ref_put ( &srpcmd->refcnt );
}
static void srpcmd_free ( struct refcnt refcnt) [static]

Free SRP command.

Parameters:
refcntReference count

Definition at line 184 of file srp.c.

References assert, container_of, free, srp_command::list, list_empty, srp_command::srpdev, and srpdev_put().

Referenced by srpdev_scsi_command().

                                                  {
        struct srp_command *srpcmd =
                container_of ( refcnt, struct srp_command, refcnt );

        assert ( list_empty ( &srpcmd->list ) );

        srpdev_put ( srpcmd->srpdev );
        free ( srpcmd );
}
static void srpcmd_close ( struct srp_command srpcmd,
int  rc 
) [static]

Close SRP command.

Parameters:
srpcmdSRP command
rcReason for close

Definition at line 200 of file srp.c.

References DBGC, INIT_LIST_HEAD, intf_shutdown(), srp_command::list, list_del, list_empty, srp_command::scsi, srpcmd_put(), srp_command::srpdev, strerror(), and srp_command::tag.

Referenced by srp_rsp(), srpdev_close(), and srpdev_scsi_command().

                                                                {
        struct srp_device *srpdev = srpcmd->srpdev;

        if ( rc != 0 ) {
                DBGC ( srpdev, "SRP %p tag %08x closed: %s\n",
                       srpdev, srpcmd->tag, strerror ( rc ) );
        }

        /* Remove from list of commands */
        if ( ! list_empty ( &srpcmd->list ) ) {
                list_del ( &srpcmd->list );
                INIT_LIST_HEAD ( &srpcmd->list );
                srpcmd_put ( srpcmd );
        }

        /* Shut down interfaces */
        intf_shutdown ( &srpcmd->scsi, rc );
}
static void srpdev_close ( struct srp_device srpdev,
int  rc 
) [static]

Close SRP device.

Parameters:
srpdevSRP device
rcReason for close

Definition at line 225 of file srp.c.

References srp_device::commands, DBGC, intf_shutdown(), srp_command::list, list_for_each_entry_safe, srp_device::scsi, srp_device::socket, srpcmd_close(), srpcmd_get(), srpcmd_put(), and strerror().

Referenced by srp_open(), and srpdev_deliver().

                                                               {
        struct srp_command *srpcmd;
        struct srp_command *tmp;

        if ( rc != 0 ) {
                DBGC ( srpdev, "SRP %p closed: %s\n",
                       srpdev, strerror ( rc ) );
        }

        /* Shut down interfaces */
        intf_shutdown ( &srpdev->socket, rc );
        intf_shutdown ( &srpdev->scsi, rc );

        /* Shut down any active commands */
        list_for_each_entry_safe ( srpcmd, tmp, &srpdev->commands, list ) {
                srpcmd_get ( srpcmd );
                srpcmd_close ( srpcmd, rc );
                srpcmd_put ( srpcmd );
        }
}
static struct srp_command* srp_find_tag ( struct srp_device srpdev,
uint32_t  tag 
) [static, read]

Identify SRP command by tag.

Parameters:
srpdevSRP device
tagCommand tag
Return values:
srpcmdSRP command, or NULL

Definition at line 253 of file srp.c.

References srp_device::commands, srp_command::list, list_for_each_entry, NULL, and srp_command::tag.

Referenced by srp_new_tag(), and srp_rsp().

                                                          {
        struct srp_command *srpcmd;

        list_for_each_entry ( srpcmd, &srpdev->commands, list ) {
                if ( srpcmd->tag == tag )
                        return srpcmd;
        }
        return NULL;
}
static int srp_new_tag ( struct srp_device srpdev) [static]

Choose an SRP command tag.

Parameters:
srpdevSRP device
Return values:
tagNew tag, or negative error

Definition at line 270 of file srp.c.

References EADDRINUSE, NULL, and srp_find_tag().

Referenced by srp_open(), and srpdev_scsi_command().

                                                     {
        static uint16_t tag_idx;
        unsigned int i;

        for ( i = 0 ; i < 65536 ; i++ ) {
                tag_idx++;
                if ( srp_find_tag ( srpdev, tag_idx ) == NULL )
                        return tag_idx;
        }
        return -EADDRINUSE;
}
static int srp_login ( struct srp_device srpdev,
union srp_port_id initiator,
union srp_port_id target,
uint32_t  tag 
) [static]

Transmit SRP login request.

Parameters:
srpdevSRP device
initiatorInitiator port ID
targetTarget port ID
tagCommand tag
Return values:
rcReturn status code

Definition at line 291 of file srp.c.

References io_buffer::data, DBGC, DBGC_HDA, srp_tag::dwords, ENOMEM, htonl, srp_login_req::initiator, iob_len(), iob_put, srp_login_req::max_i_t_iu_len, memcpy(), memset(), rc, srp_login_req::required_buffer_formats, srp_device::socket, SRP_LOGIN_REQ, SRP_LOGIN_REQ_FMT_DDBD, SRP_MAX_I_T_IU_LEN, SRP_TAG_MAGIC, strerror(), srp_login_req::tag, srp_login_req::target, srp_login_req::type, xfer_alloc_iob(), and xfer_deliver_iob().

Referenced by srp_open().

                                                                 {
        struct io_buffer *iobuf;
        struct srp_login_req *login_req;
        int rc;

        /* Allocate I/O buffer */
        iobuf = xfer_alloc_iob ( &srpdev->socket, sizeof ( *login_req ) );
        if ( ! iobuf )
                return -ENOMEM;

        /* Construct login request IU */
        login_req = iob_put ( iobuf, sizeof ( *login_req ) );
        memset ( login_req, 0, sizeof ( *login_req ) );
        login_req->type = SRP_LOGIN_REQ;
        login_req->tag.dwords[0] = htonl ( SRP_TAG_MAGIC );
        login_req->tag.dwords[1] = htonl ( tag );
        login_req->max_i_t_iu_len = htonl ( SRP_MAX_I_T_IU_LEN );
        login_req->required_buffer_formats = SRP_LOGIN_REQ_FMT_DDBD;
        memcpy ( &login_req->initiator, initiator,
                 sizeof ( login_req->initiator ) );
        memcpy ( &login_req->target, target, sizeof ( login_req->target ) );

        DBGC ( srpdev, "SRP %p tag %08x LOGIN_REQ:\n", srpdev, tag );
        DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) );

        /* Send login request IU */
        if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) {
                DBGC ( srpdev, "SRP %p tag %08x could not send LOGIN_REQ: "
                       "%s\n", srpdev, tag, strerror ( rc ) );
                return rc;
        }

        return 0;
}
static int srp_login_rsp ( struct srp_device srpdev,
const void *  data,
size_t  len 
) [static]

Receive SRP login response.

Parameters:
srpdevSRP device
dataSRP IU
lenLength of SRP IU
Return values:
rcReturn status code

Definition at line 335 of file srp.c.

References data, DBGC, DBGC_HDA, srp_tag::dwords, EINVAL, srp_device::logged_in, ntohl, srp_device::scsi, srp_login_rsp::tag, and xfer_window_changed().

Referenced by srpdev_deliver().

                                                          {
        const struct srp_login_rsp *login_rsp = data;

        /* Sanity check */
        if ( len < sizeof ( *login_rsp ) ) {
                DBGC ( srpdev, "SRP %p LOGIN_RSP too short (%zd bytes)\n",
                       srpdev, len );
                return -EINVAL;
        }
        DBGC ( srpdev, "SRP %p tag %08x LOGIN_RSP:\n",
               srpdev, ntohl ( login_rsp->tag.dwords[1] ) );
        DBGC_HDA ( srpdev, 0, data, len );

        /* Mark as logged in */
        srpdev->logged_in = 1;
        DBGC ( srpdev, "SRP %p logged in\n", srpdev );

        /* Notify of window change */
        xfer_window_changed ( &srpdev->scsi );

        return 0;
}
static int srp_login_rej ( struct srp_device srpdev,
const void *  data,
size_t  len 
) [static]

Receive SRP login rejection.

Parameters:
srpdevSRP device
dataSRP IU
lenLength of SRP IU
Return values:
rcReturn status code

Definition at line 367 of file srp.c.

References data, DBGC, DBGC_HDA, srp_tag::dwords, EACCES, EINVAL, EPERM_LOGIN_REJ, ntohl, srp_login_rej::reason, reason, SRP_LOGIN_REJ_REASON_DEFINED, and srp_login_rej::tag.

Referenced by srpdev_deliver().

                                                          {
        const struct srp_login_rej *login_rej = data;
        uint32_t reason;

        /* Sanity check */
        if ( len < sizeof ( *login_rej ) ) {
                DBGC ( srpdev, "SRP %p LOGIN_REJ too short (%zd bytes)\n",
                       srpdev, len );
                return -EINVAL;
        }
        reason = ntohl ( login_rej->reason );
        DBGC ( srpdev, "SRP %p tag %08x LOGIN_REJ reason %08x:\n",
               srpdev, ntohl ( login_rej->tag.dwords[1] ), reason );
        DBGC_HDA ( srpdev, 0, data, len );

        /* Login rejection always indicates an error */
        return ( SRP_LOGIN_REJ_REASON_DEFINED ( reason ) ?
                 -EPERM_LOGIN_REJ ( reason ) : -EACCES );
}
static int srp_cmd ( struct srp_device srpdev,
struct scsi_cmd command,
uint32_t  tag 
) [static]

Transmit SRP SCSI command.

Parameters:
srpdevSRP device
commandSCSI command
tagCommand tag
Return values:
rcReturn status code

Definition at line 396 of file srp.c.

References srp_memory_descriptor::address, scsi_cmd::cdb, srp_cmd::cdb, cmd, cpu_to_be64, srp_cmd::data_buffer_formats, scsi_cmd::data_in, scsi_cmd::data_in_len, scsi_cmd::data_out, scsi_cmd::data_out_len, DBGC, DBGC2, srp_tag::dwords, EBUSY, ENOMEM, srp_memory_descriptor::handle, htonl, iob_put, srp_memory_descriptor::len, srp_device::logged_in, scsi_cmd::lun, srp_cmd::lun, memcpy(), srp_device::memory_handle, memset(), ntohl, rc, SCSI_CDB_DATA, SCSI_CDB_FORMAT, srp_device::socket, SRP_CMD, SRP_CMD_DI_FMT_DIRECT, SRP_CMD_DO_FMT_DIRECT, SRP_MAX_I_T_IU_LEN, SRP_TAG_MAGIC, strerror(), srp_cmd::tag, srp_cmd::type, user_to_phys(), xfer_alloc_iob(), and xfer_deliver_iob().

                                    {
        struct io_buffer *iobuf;
        struct srp_cmd *cmd;
        struct srp_memory_descriptor *data_out;
        struct srp_memory_descriptor *data_in;
        int rc;

        /* Sanity check */
        if ( ! srpdev->logged_in ) {
                DBGC ( srpdev, "SRP %p tag %08x cannot send CMD before "
                       "login completes\n", srpdev, tag );
                return -EBUSY;
        }

        /* Allocate I/O buffer */
        iobuf = xfer_alloc_iob ( &srpdev->socket, SRP_MAX_I_T_IU_LEN );
        if ( ! iobuf )
                return -ENOMEM;

        /* Construct base portion */
        cmd = iob_put ( iobuf, sizeof ( *cmd ) );
        memset ( cmd, 0, sizeof ( *cmd ) );
        cmd->type = SRP_CMD;
        cmd->tag.dwords[0] = htonl ( SRP_TAG_MAGIC );
        cmd->tag.dwords[1] = htonl ( tag );
        memcpy ( &cmd->lun, &command->lun, sizeof ( cmd->lun ) );
        memcpy ( &cmd->cdb, &command->cdb, sizeof ( cmd->cdb ) );

        /* Construct data-out descriptor, if present */
        if ( command->data_out ) {
                cmd->data_buffer_formats |= SRP_CMD_DO_FMT_DIRECT;
                data_out = iob_put ( iobuf, sizeof ( *data_out ) );
                data_out->address =
                    cpu_to_be64 ( user_to_phys ( command->data_out, 0 ) );
                data_out->handle = ntohl ( srpdev->memory_handle );
                data_out->len = ntohl ( command->data_out_len );
        }

        /* Construct data-in descriptor, if present */
        if ( command->data_in ) {
                cmd->data_buffer_formats |= SRP_CMD_DI_FMT_DIRECT;
                data_in = iob_put ( iobuf, sizeof ( *data_in ) );
                data_in->address =
                     cpu_to_be64 ( user_to_phys ( command->data_in, 0 ) );
                data_in->handle = ntohl ( srpdev->memory_handle );
                data_in->len = ntohl ( command->data_in_len );
        }

        DBGC2 ( srpdev, "SRP %p tag %08x CMD " SCSI_CDB_FORMAT "\n",
                srpdev, tag, SCSI_CDB_DATA ( cmd->cdb ) );

        /* Send IU */
        if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) {
                DBGC ( srpdev, "SRP %p tag %08x could not send CMD: %s\n",
                       srpdev, tag, strerror ( rc ) );
                return rc;
        }

        return 0;
}
static int srp_rsp ( struct srp_device srpdev,
const void *  data,
size_t  len 
) [static]

Receive SRP SCSI response.

Parameters:
srpdevSRP device
dataSRP IU
lenLength of SRP IU
Return values:
rcReturns status code

Definition at line 467 of file srp.c.

References data, srp_rsp::data_in_residual_count, srp_rsp::data_out_residual_count, DBGC, DBGC2, srp_tag::dwords, EINVAL, ENOENT, memset(), ntohl, scsi_rsp::overrun, rsp, srp_command::scsi, scsi_parse_sense(), scsi_response(), scsi_rsp::sense, srp_find_tag(), srp_rsp_response_data_len(), srp_rsp_sense_data(), srp_rsp_sense_data_len(), SRP_RSP_VALID_DIOVER, SRP_RSP_VALID_DIUNDER, SRP_RSP_VALID_DOOVER, SRP_RSP_VALID_DOUNDER, SRP_RSP_VALID_RSPVALID, SRP_RSP_VALID_SNSVALID, srpcmd_close(), srpcmd_get(), srpcmd_put(), scsi_rsp::status, srp_rsp::status, srp_rsp::tag, and srp_rsp::valid.

Referenced by srpdev_deliver().

                                                    {
        const struct srp_rsp *rsp = data;
        struct srp_command *srpcmd;
        struct scsi_rsp response;
        ssize_t data_out_residual_count;
        ssize_t data_in_residual_count;

        /* Sanity check */
        if ( ( len < sizeof ( *rsp ) ) ||
             ( len < ( sizeof ( *rsp ) +
                       srp_rsp_response_data_len ( rsp ) +
                       srp_rsp_sense_data_len ( rsp ) ) ) ) {
                DBGC ( srpdev, "SRP %p RSP too short (%zd bytes)\n",
                       srpdev, len );
                return -EINVAL;
        }
        DBGC2 ( srpdev, "SRP %p tag %08x RSP stat %02x dores %08x dires "
                "%08x valid %02x%s%s%s%s%s%s\n",
                srpdev, ntohl ( rsp->tag.dwords[1] ), rsp->status,
                ntohl ( rsp->data_out_residual_count ),
                ntohl ( rsp->data_in_residual_count ), rsp->valid,
                ( ( rsp->valid & SRP_RSP_VALID_DIUNDER ) ? " diunder" : "" ),
                ( ( rsp->valid & SRP_RSP_VALID_DIOVER ) ? " diover" : "" ),
                ( ( rsp->valid & SRP_RSP_VALID_DOUNDER ) ? " dounder" : "" ),
                ( ( rsp->valid & SRP_RSP_VALID_DOOVER ) ? " doover" : "" ),
                ( ( rsp->valid & SRP_RSP_VALID_SNSVALID ) ? " sns" : "" ),
                ( ( rsp->valid & SRP_RSP_VALID_RSPVALID ) ? " rsp" : "" ) );

        /* Identify command by tag */
        srpcmd = srp_find_tag ( srpdev, ntohl ( rsp->tag.dwords[1] ) );
        if ( ! srpcmd ) {
                DBGC ( srpdev, "SRP %p tag %08x unrecognised RSP\n",
                       srpdev, ntohl ( rsp->tag.dwords[1] ) );
                return -ENOENT;
        }

        /* Hold command reference for remainder of function */
        srpcmd_get ( srpcmd );

        /* Build SCSI response */
        memset ( &response, 0, sizeof ( response ) );
        response.status = rsp->status;
        data_out_residual_count = ntohl ( rsp->data_out_residual_count );
        data_in_residual_count = ntohl ( rsp->data_in_residual_count );
        if ( rsp->valid & SRP_RSP_VALID_DOOVER ) {
                response.overrun = data_out_residual_count;
        } else if ( rsp->valid & SRP_RSP_VALID_DOUNDER ) {
                response.overrun = -(data_out_residual_count);
        } else if ( rsp->valid & SRP_RSP_VALID_DIOVER ) {
                response.overrun = data_in_residual_count;
        } else if ( rsp->valid & SRP_RSP_VALID_DIUNDER ) {
                response.overrun = -(data_in_residual_count);
        }
        scsi_parse_sense ( srp_rsp_sense_data ( rsp ),
                           srp_rsp_sense_data_len ( rsp ), &response.sense );

        /* Report SCSI response */
        scsi_response ( &srpcmd->scsi, &response );

        /* Close SCSI command */
        srpcmd_close ( srpcmd, 0 );

        /* Drop temporary command reference */
        srpcmd_put ( srpcmd );

        return 0;
}
static int srp_unrecognised ( struct srp_device srpdev,
const void *  data,
size_t  len 
) [static]

Receive SRP unrecognised response IU.

Parameters:
srpdevSRP device
dataSRP IU
lenLength of SRP IU
Return values:
rcReturns status code

Definition at line 544 of file srp.c.

References common, data, DBGC, DBGC_HDA, srp_tag::dwords, ENOTSUP, ntohl, srp_common::tag, and srp_common::type.

Referenced by srpdev_deliver().

                                                             {
        const struct srp_common *common = data;

        DBGC ( srpdev, "SRP %p tag %08x unrecognised IU type %02x:\n",
               srpdev, ntohl ( common->tag.dwords[1] ), common->type );
        DBGC_HDA ( srpdev, 0, data, len );

        return -ENOTSUP;
}
static int srpdev_scsi_command ( struct srp_device srpdev,
struct interface parent,
struct scsi_cmd command 
) [static]

Issue SRP SCSI command.

Parameters:
srpdevSRP device
parentParent interface
commandSCSI command
Return values:
tagCommand tag, or negative error

Definition at line 572 of file srp.c.

References srp_device::commands, ENOMEM, intf_init(), intf_plug_plug(), srp_command::list, list_add, rc, ref_init, srp_command::refcnt, srp_command::scsi, srp_new_tag(), srpcmd_close(), srpcmd_free(), srp_command::srpdev, srpdev_get(), srp_command::tag, tag, and zalloc().

                                                            {
        struct srp_command *srpcmd;
        int tag;
        int rc;

        /* Allocate command tag */
        tag = srp_new_tag ( srpdev );
        if ( tag < 0 ) {
                rc = tag;
                goto err_tag;
        }

        /* Allocate and initialise structure */
        srpcmd = zalloc ( sizeof ( *srpcmd ) );
        if ( ! srpcmd ) {
                rc = -ENOMEM;
                goto err_zalloc;
        }
        ref_init ( &srpcmd->refcnt, srpcmd_free );
        intf_init ( &srpcmd->scsi, &srpcmd_scsi_desc, &srpcmd->refcnt );
        srpcmd->srpdev = srpdev_get ( srpdev );
        list_add ( &srpcmd->list, &srpdev->commands );
        srpcmd->tag = tag;

        /* Send command IU */
        if ( ( rc = srp_cmd ( srpdev, command, srpcmd->tag ) ) != 0 )
                goto err_cmd;

        /* Attach to parent interface, leave reference with command
         * list, and return.
         */
        intf_plug_plug ( &srpcmd->scsi, parent );
        return srpcmd->tag;

 err_cmd:
        srpcmd_close ( srpcmd, rc );
 err_zalloc:
 err_tag:
        return rc;
}
static int srpdev_deliver ( struct srp_device srpdev,
struct io_buffer iobuf,
struct xfer_metadata *meta  __unused 
) [static]

Receive data from SRP socket.

Parameters:
srpdevSRP device
iobufDatagram I/O buffer
metaData transfer metadata
Return values:
rcReturn status code

Definition at line 623 of file srp.c.

References common, io_buffer::data, data, DBGC, DBGC_HDA, EINVAL, free_iob(), iob_len(), len, rc, SRP_LOGIN_REJ, srp_login_rej(), SRP_LOGIN_RSP, srp_login_rsp(), srp_rsp(), SRP_RSP, srp_unrecognised(), srpdev_close(), strerror(), srp_common::type, and type.

                                                                  {
        struct srp_common *common = iobuf->data;
        int ( * type ) ( struct srp_device *srp, const void *data, size_t len );
        int rc;

        /* Sanity check */
        if ( iob_len ( iobuf ) < sizeof ( *common ) ) {
                DBGC ( srpdev, "SRP %p IU too short (%zd bytes)\n",
                       srpdev, iob_len ( iobuf ) );
                rc = -EINVAL;
                goto err;
        }

        /* Determine IU type */
        switch ( common->type ) {
        case SRP_LOGIN_RSP:
                type = srp_login_rsp;
                break;
        case SRP_LOGIN_REJ:
                type = srp_login_rej;
                break;
        case SRP_RSP:
                type = srp_rsp;
                break;
        default:
                type = srp_unrecognised;
                break;
        }

        /* Handle IU */
        if ( ( rc = type ( srpdev, iobuf->data, iob_len ( iobuf ) ) ) != 0 )
                goto err;

        free_iob ( iobuf );
        return 0;

 err:
        DBGC ( srpdev, "SRP %p closing due to received IU (%s):\n",
               srpdev, strerror ( rc ) );
        DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) );
        free_iob ( iobuf );
        srpdev_close ( srpdev, rc );
        return rc;
}
static size_t srpdev_window ( struct srp_device srpdev) [static]

Check SRP device flow-control window.

Parameters:
srpdevSRP device
Return values:
lenLength of window

Definition at line 676 of file srp.c.

References srp_device::logged_in.

                                                          {
        return ( srpdev->logged_in ? ~( ( size_t ) 0 ) : 0 );
}
int srp_open ( struct interface block,
struct interface socket,
union srp_port_id initiator,
union srp_port_id target,
uint32_t  memory_handle,
struct scsi_lun lun 
)

Open SRP device.

Parameters:
blockBlock control interface
socketSocket interface
initiatorInitiator port ID
targetTarget port ID
memory_handleRDMA memory handle
lunSCSI LUN
Return values:
rcReturn status code

Definition at line 713 of file srp.c.

References assert, srp_device::commands, DBGC, srp_port_id::dwords, ENOMEM, INIT_LIST_HEAD, intf_init(), intf_plug_plug(), srp_device::memory_handle, ntohl, NULL, rc, ref_init, ref_put, srp_device::refcnt, srp_device::scsi, scsi_open(), srp_device::socket, srp_login(), srp_new_tag(), srpdev_close(), strerror(), tag, and zalloc().

Referenced by ib_srp_open().

                                                              {
        struct srp_device *srpdev;
        int tag;
        int rc;

        /* Allocate and initialise structure */
        srpdev = zalloc ( sizeof ( *srpdev ) );
        if ( ! srpdev ) {
                rc = -ENOMEM;
                goto err_zalloc;
        }
        ref_init ( &srpdev->refcnt, NULL );
        intf_init ( &srpdev->scsi, &srpdev_scsi_desc, &srpdev->refcnt );
        intf_init ( &srpdev->socket, &srpdev_socket_desc, &srpdev->refcnt );
        INIT_LIST_HEAD ( &srpdev->commands );
        srpdev->memory_handle = memory_handle;
        DBGC ( srpdev, "SRP %p %08x%08x%08x%08x->%08x%08x%08x%08x\n", srpdev,
               ntohl ( initiator->dwords[0] ), ntohl ( initiator->dwords[1] ),
               ntohl ( initiator->dwords[2] ), ntohl ( initiator->dwords[3] ),
               ntohl ( target->dwords[0] ), ntohl ( target->dwords[1] ),
               ntohl ( target->dwords[2] ), ntohl ( target->dwords[3] ) );

        /* Attach to socket interface and initiate login */
        intf_plug_plug ( &srpdev->socket, socket );
        tag = srp_new_tag ( srpdev );
        assert ( tag >= 0 ); /* Cannot fail when no commands in progress */
        if ( ( rc = srp_login ( srpdev, initiator, target, tag ) ) != 0 )
                goto err_login;

        /* Attach SCSI device to parent interface */
        if ( ( rc = scsi_open ( block, &srpdev->scsi, lun ) ) != 0 ) {
                DBGC ( srpdev, "SRP %p could not create SCSI device: %s\n",
                       srpdev, strerror ( rc ) );
                goto err_scsi_open;
        }

        /* Mortalise self and return */
        ref_put ( &srpdev->refcnt );
        return 0;

 err_scsi_open:
 err_login:
        srpdev_close ( srpdev, rc );
        ref_put ( &srpdev->refcnt );
 err_zalloc:
        return rc;
}

Variable Documentation

Initial value:

SRP command SCSI interface operations.

Definition at line 556 of file srp.c.

Initial value:

SRP command SCSI interface descriptor.

Definition at line 561 of file srp.c.

Initial value:

SRP device socket interface operations.

Definition at line 681 of file srp.c.

Initial value:

SRP device socket interface descriptor.

Definition at line 687 of file srp.c.

Initial value:

SRP device SCSI interface operations.

Definition at line 692 of file srp.c.

Initial value:

SRP device SCSI interface descriptor.

Definition at line 699 of file srp.c.