2009-07-17 23:11:42 +02:00
|
|
|
/*
|
|
|
|
* 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 <string.h>
|
|
|
|
#include <errno.h>
|
2010-04-19 21:16:01 +02:00
|
|
|
#include <ipxe/scsi.h>
|
|
|
|
#include <ipxe/xfer.h>
|
|
|
|
#include <ipxe/features.h>
|
|
|
|
#include <ipxe/ib_srp.h>
|
|
|
|
#include <ipxe/srp.h>
|
2009-07-17 23:11:42 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @file
|
|
|
|
*
|
|
|
|
* SCSI RDMA Protocol
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
FEATURE ( FEATURE_PROTOCOL, "SRP", DHCP_EB_FEATURE_SRP, 1 );
|
|
|
|
|
|
|
|
/** Tag to be used for next SRP IU */
|
|
|
|
static unsigned int srp_tag = 0;
|
|
|
|
|
|
|
|
static void srp_login ( struct srp_device *srp );
|
|
|
|
static void srp_cmd ( struct srp_device *srp );
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mark SRP SCSI command as complete
|
|
|
|
*
|
|
|
|
* @v srp SRP device
|
|
|
|
* @v rc Status code
|
|
|
|
*/
|
|
|
|
static void srp_scsi_done ( struct srp_device *srp, int rc ) {
|
|
|
|
if ( srp->command )
|
|
|
|
srp->command->rc = rc;
|
|
|
|
srp->command = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle SRP session failure
|
|
|
|
*
|
|
|
|
* @v srp SRP device
|
|
|
|
* @v rc Reason for failure
|
|
|
|
*/
|
|
|
|
static void srp_fail ( struct srp_device *srp, int rc ) {
|
|
|
|
|
|
|
|
/* Close underlying socket */
|
2010-06-16 02:31:29 +02:00
|
|
|
intf_restart ( &srp->socket, rc );
|
2009-07-17 23:11:42 +02:00
|
|
|
|
|
|
|
/* Clear session state */
|
|
|
|
srp->state = 0;
|
|
|
|
|
2009-08-10 03:20:21 +02:00
|
|
|
/* If we have reached the retry limit, report the failure */
|
2009-07-17 23:11:42 +02:00
|
|
|
if ( srp->retry_count >= SRP_MAX_RETRIES ) {
|
|
|
|
srp_scsi_done ( srp, rc );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-08-10 03:20:21 +02:00
|
|
|
/* Otherwise, increment the retry count and try to reopen the
|
|
|
|
* connection
|
|
|
|
*/
|
|
|
|
srp->retry_count++;
|
2009-07-17 23:11:42 +02:00
|
|
|
srp_login ( srp );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initiate SRP login
|
|
|
|
*
|
|
|
|
* @v srp SRP device
|
|
|
|
*/
|
|
|
|
static void srp_login ( struct srp_device *srp ) {
|
|
|
|
struct io_buffer *iobuf;
|
|
|
|
struct srp_login_req *login_req;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
assert ( ! ( srp->state & SRP_STATE_SOCKET_OPEN ) );
|
|
|
|
|
|
|
|
/* Open underlying socket */
|
|
|
|
if ( ( rc = srp->transport->connect ( srp ) ) != 0 ) {
|
|
|
|
DBGC ( srp, "SRP %p could not open socket: %s\n",
|
|
|
|
srp, strerror ( rc ) );
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
srp->state |= SRP_STATE_SOCKET_OPEN;
|
|
|
|
|
|
|
|
/* Allocate I/O buffer */
|
|
|
|
iobuf = xfer_alloc_iob ( &srp->socket, sizeof ( *login_req ) );
|
|
|
|
if ( ! iobuf ) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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[1] = htonl ( ++srp_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->port_ids, &srp->port_ids,
|
|
|
|
sizeof ( login_req->port_ids ) );
|
|
|
|
|
|
|
|
DBGC2 ( srp, "SRP %p TX login request tag %08x%08x\n",
|
|
|
|
srp, ntohl ( login_req->tag.dwords[0] ),
|
|
|
|
ntohl ( login_req->tag.dwords[1] ) );
|
|
|
|
DBGC2_HDA ( srp, 0, iobuf->data, iob_len ( iobuf ) );
|
|
|
|
|
|
|
|
/* Send login request IU */
|
|
|
|
if ( ( rc = xfer_deliver_iob ( &srp->socket, iobuf ) ) != 0 ) {
|
|
|
|
DBGC ( srp, "SRP %p could not send login request: %s\n",
|
|
|
|
srp, strerror ( rc ) );
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
err:
|
|
|
|
srp_fail ( srp, rc );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle SRP login response
|
|
|
|
*
|
|
|
|
* @v srp SRP device
|
|
|
|
* @v iobuf I/O buffer
|
|
|
|
* @ret rc Return status code
|
|
|
|
*/
|
|
|
|
static int srp_login_rsp ( struct srp_device *srp, struct io_buffer *iobuf ) {
|
|
|
|
struct srp_login_rsp *login_rsp = iobuf->data;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
DBGC2 ( srp, "SRP %p RX login response tag %08x%08x\n",
|
|
|
|
srp, ntohl ( login_rsp->tag.dwords[0] ),
|
|
|
|
ntohl ( login_rsp->tag.dwords[1] ) );
|
|
|
|
|
|
|
|
/* Sanity check */
|
|
|
|
if ( iob_len ( iobuf ) < sizeof ( *login_rsp ) ) {
|
|
|
|
DBGC ( srp, "SRP %p RX login response too short (%zd bytes)\n",
|
|
|
|
srp, iob_len ( iobuf ) );
|
|
|
|
rc = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
DBGC ( srp, "SRP %p logged in\n", srp );
|
|
|
|
|
|
|
|
/* Mark as logged in */
|
|
|
|
srp->state |= SRP_STATE_LOGGED_IN;
|
|
|
|
|
|
|
|
/* Reset error counter */
|
|
|
|
srp->retry_count = 0;
|
|
|
|
|
|
|
|
/* Issue pending command */
|
|
|
|
srp_cmd ( srp );
|
|
|
|
|
|
|
|
rc = 0;
|
|
|
|
out:
|
|
|
|
free_iob ( iobuf );
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle SRP login rejection
|
|
|
|
*
|
|
|
|
* @v srp SRP device
|
|
|
|
* @v iobuf I/O buffer
|
|
|
|
* @ret rc Return status code
|
|
|
|
*/
|
|
|
|
static int srp_login_rej ( struct srp_device *srp, struct io_buffer *iobuf ) {
|
|
|
|
struct srp_login_rej *login_rej = iobuf->data;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
DBGC2 ( srp, "SRP %p RX login rejection tag %08x%08x\n",
|
|
|
|
srp, ntohl ( login_rej->tag.dwords[0] ),
|
|
|
|
ntohl ( login_rej->tag.dwords[1] ) );
|
|
|
|
|
|
|
|
/* Sanity check */
|
|
|
|
if ( iob_len ( iobuf ) < sizeof ( *login_rej ) ) {
|
|
|
|
DBGC ( srp, "SRP %p RX login rejection too short (%zd "
|
|
|
|
"bytes)\n", srp, iob_len ( iobuf ) );
|
|
|
|
rc = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Login rejection always indicates an error */
|
|
|
|
DBGC ( srp, "SRP %p login rejected (reason %08x)\n",
|
|
|
|
srp, ntohl ( login_rej->reason ) );
|
|
|
|
rc = -EPERM;
|
|
|
|
|
|
|
|
out:
|
|
|
|
free_iob ( iobuf );
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Transmit SRP SCSI command
|
|
|
|
*
|
|
|
|
* @v srp SRP device
|
|
|
|
*/
|
|
|
|
static void srp_cmd ( struct srp_device *srp ) {
|
|
|
|
struct io_buffer *iobuf;
|
|
|
|
struct srp_cmd *cmd;
|
|
|
|
struct srp_memory_descriptor *data_out;
|
|
|
|
struct srp_memory_descriptor *data_in;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
assert ( srp->state & SRP_STATE_LOGGED_IN );
|
|
|
|
|
|
|
|
/* Allocate I/O buffer */
|
|
|
|
iobuf = xfer_alloc_iob ( &srp->socket, SRP_MAX_I_T_IU_LEN );
|
|
|
|
if ( ! iobuf ) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Construct base portion */
|
|
|
|
cmd = iob_put ( iobuf, sizeof ( *cmd ) );
|
|
|
|
memset ( cmd, 0, sizeof ( *cmd ) );
|
|
|
|
cmd->type = SRP_CMD;
|
|
|
|
cmd->tag.dwords[1] = htonl ( ++srp_tag );
|
|
|
|
cmd->lun = srp->lun;
|
|
|
|
memcpy ( &cmd->cdb, &srp->command->cdb, sizeof ( cmd->cdb ) );
|
|
|
|
|
|
|
|
/* Construct data-out descriptor, if present */
|
|
|
|
if ( srp->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 ( srp->command->data_out, 0 ) );
|
|
|
|
data_out->handle = ntohl ( srp->memory_handle );
|
|
|
|
data_out->len = ntohl ( srp->command->data_out_len );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Construct data-in descriptor, if present */
|
|
|
|
if ( srp->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 ( srp->command->data_in, 0 ) );
|
|
|
|
data_in->handle = ntohl ( srp->memory_handle );
|
|
|
|
data_in->len = ntohl ( srp->command->data_in_len );
|
|
|
|
}
|
|
|
|
|
|
|
|
DBGC2 ( srp, "SRP %p TX SCSI command tag %08x%08x\n", srp,
|
|
|
|
ntohl ( cmd->tag.dwords[0] ), ntohl ( cmd->tag.dwords[1] ) );
|
|
|
|
DBGC2_HDA ( srp, 0, iobuf->data, iob_len ( iobuf ) );
|
|
|
|
|
|
|
|
/* Send IU */
|
|
|
|
if ( ( rc = xfer_deliver_iob ( &srp->socket, iobuf ) ) != 0 ) {
|
|
|
|
DBGC ( srp, "SRP %p could not send command: %s\n",
|
|
|
|
srp, strerror ( rc ) );
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
err:
|
|
|
|
srp_fail ( srp, rc );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle SRP SCSI response
|
|
|
|
*
|
|
|
|
* @v srp SRP device
|
|
|
|
* @v iobuf I/O buffer
|
|
|
|
* @ret rc Returns status code
|
|
|
|
*/
|
|
|
|
static int srp_rsp ( struct srp_device *srp, struct io_buffer *iobuf ) {
|
|
|
|
struct srp_rsp *rsp = iobuf->data;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
DBGC2 ( srp, "SRP %p RX SCSI response tag %08x%08x\n", srp,
|
|
|
|
ntohl ( rsp->tag.dwords[0] ), ntohl ( rsp->tag.dwords[1] ) );
|
|
|
|
|
|
|
|
/* Sanity check */
|
|
|
|
if ( iob_len ( iobuf ) < sizeof ( *rsp ) ) {
|
|
|
|
DBGC ( srp, "SRP %p RX SCSI response too short (%zd bytes)\n",
|
|
|
|
srp, iob_len ( iobuf ) );
|
|
|
|
rc = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Report SCSI errors */
|
|
|
|
if ( rsp->status != 0 ) {
|
|
|
|
DBGC ( srp, "SRP %p response status %02x\n",
|
|
|
|
srp, rsp->status );
|
|
|
|
if ( srp_rsp_sense_data ( rsp ) ) {
|
|
|
|
DBGC ( srp, "SRP %p sense data:\n", srp );
|
|
|
|
DBGC_HDA ( srp, 0, srp_rsp_sense_data ( rsp ),
|
|
|
|
srp_rsp_sense_data_len ( rsp ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( rsp->valid & ( SRP_RSP_VALID_DOUNDER | SRP_RSP_VALID_DOOVER ) ) {
|
|
|
|
DBGC ( srp, "SRP %p response data-out %srun by %#x bytes\n",
|
|
|
|
srp, ( ( rsp->valid & SRP_RSP_VALID_DOUNDER )
|
|
|
|
? "under" : "over" ),
|
|
|
|
ntohl ( rsp->data_out_residual_count ) );
|
|
|
|
}
|
|
|
|
if ( rsp->valid & ( SRP_RSP_VALID_DIUNDER | SRP_RSP_VALID_DIOVER ) ) {
|
|
|
|
DBGC ( srp, "SRP %p response data-in %srun by %#x bytes\n",
|
|
|
|
srp, ( ( rsp->valid & SRP_RSP_VALID_DIUNDER )
|
|
|
|
? "under" : "over" ),
|
|
|
|
ntohl ( rsp->data_in_residual_count ) );
|
|
|
|
}
|
|
|
|
srp->command->status = rsp->status;
|
|
|
|
|
|
|
|
/* Mark SCSI command as complete */
|
|
|
|
srp_scsi_done ( srp, 0 );
|
|
|
|
|
|
|
|
rc = 0;
|
|
|
|
out:
|
|
|
|
free_iob ( iobuf );
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle SRP unrecognised response
|
|
|
|
*
|
|
|
|
* @v srp SRP device
|
|
|
|
* @v iobuf I/O buffer
|
|
|
|
* @ret rc Returns status code
|
|
|
|
*/
|
|
|
|
static int srp_unrecognised ( struct srp_device *srp,
|
|
|
|
struct io_buffer *iobuf ) {
|
|
|
|
struct srp_common *common = iobuf->data;
|
|
|
|
|
|
|
|
DBGC ( srp, "SRP %p RX unrecognised IU tag %08x%08x type %02x\n",
|
|
|
|
srp, ntohl ( common->tag.dwords[0] ),
|
|
|
|
ntohl ( common->tag.dwords[1] ), common->type );
|
|
|
|
|
|
|
|
free_iob ( iobuf );
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Receive data from underlying socket
|
|
|
|
*
|
2010-06-16 02:31:29 +02:00
|
|
|
* @v srp SRP device
|
2009-07-17 23:11:42 +02:00
|
|
|
* @v iobuf Datagram I/O buffer
|
|
|
|
* @v meta Data transfer metadata
|
|
|
|
* @ret rc Return status code
|
|
|
|
*/
|
2010-06-16 02:31:29 +02:00
|
|
|
static int srp_xfer_deliver ( struct srp_device *srp,
|
|
|
|
struct io_buffer *iobuf,
|
|
|
|
struct xfer_metadata *meta __unused ) {
|
2009-07-17 23:11:42 +02:00
|
|
|
struct srp_common *common = iobuf->data;
|
|
|
|
int ( * type ) ( struct srp_device *srp, struct io_buffer *iobuf );
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
/* 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 ( srp, iobuf ) ) != 0 )
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
srp_fail ( srp, rc );
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** SRP data transfer interface operations */
|
2010-06-16 02:31:29 +02:00
|
|
|
static struct interface_operation srp_xfer_operations[] = {
|
|
|
|
INTF_OP ( xfer_deliver, struct srp_device *, srp_xfer_deliver ),
|
|
|
|
INTF_OP ( intf_close, struct srp_device *, srp_fail ),
|
2009-07-17 23:11:42 +02:00
|
|
|
};
|
|
|
|
|
2010-06-16 02:31:29 +02:00
|
|
|
/** SRP data transfer interface descriptor */
|
|
|
|
static struct interface_descriptor srp_xfer_desc =
|
|
|
|
INTF_DESC ( struct srp_device, socket, srp_xfer_operations );
|
|
|
|
|
2009-07-17 23:11:42 +02:00
|
|
|
/**
|
|
|
|
* Issue SCSI command via SRP
|
|
|
|
*
|
|
|
|
* @v scsi SCSI device
|
|
|
|
* @v command SCSI command
|
|
|
|
* @ret rc Return status code
|
|
|
|
*/
|
|
|
|
static int srp_command ( struct scsi_device *scsi,
|
|
|
|
struct scsi_command *command ) {
|
|
|
|
struct srp_device *srp =
|
|
|
|
container_of ( scsi->backend, struct srp_device, refcnt );
|
|
|
|
|
|
|
|
/* Store SCSI command */
|
|
|
|
if ( srp->command ) {
|
|
|
|
DBGC ( srp, "SRP %p cannot handle concurrent SCSI commands\n",
|
|
|
|
srp );
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
srp->command = command;
|
|
|
|
|
|
|
|
/* Log in or issue command as appropriate */
|
|
|
|
if ( ! ( srp->state & SRP_STATE_SOCKET_OPEN ) ) {
|
|
|
|
srp_login ( srp );
|
|
|
|
} else if ( srp->state & SRP_STATE_LOGGED_IN ) {
|
|
|
|
srp_cmd ( srp );
|
|
|
|
} else {
|
|
|
|
/* Still waiting for login; do nothing */
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Attach SRP device
|
|
|
|
*
|
|
|
|
* @v scsi SCSI device
|
|
|
|
* @v root_path Root path
|
|
|
|
*/
|
|
|
|
int srp_attach ( struct scsi_device *scsi, const char *root_path ) {
|
|
|
|
struct srp_transport_type *transport;
|
|
|
|
struct srp_device *srp;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
/* Hard-code an IB SRP back-end for now */
|
|
|
|
transport = &ib_srp_transport;
|
|
|
|
|
|
|
|
/* Allocate and initialise structure */
|
|
|
|
srp = zalloc ( sizeof ( *srp ) + transport->priv_len );
|
|
|
|
if ( ! srp ) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto err_alloc;
|
|
|
|
}
|
2010-06-15 18:33:23 +02:00
|
|
|
ref_init ( &srp->refcnt, NULL );
|
2010-06-16 02:31:29 +02:00
|
|
|
intf_init ( &srp->socket, &srp_xfer_desc, &srp->refcnt );
|
2009-07-17 23:11:42 +02:00
|
|
|
srp->transport = transport;
|
|
|
|
DBGC ( srp, "SRP %p using %s\n", srp, root_path );
|
|
|
|
|
|
|
|
/* Parse root path */
|
|
|
|
if ( ( rc = transport->parse_root_path ( srp, root_path ) ) != 0 ) {
|
|
|
|
DBGC ( srp, "SRP %p could not parse root path: %s\n",
|
|
|
|
srp, strerror ( rc ) );
|
|
|
|
goto err_parse_root_path;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Attach parent interface, mortalise self, and return */
|
|
|
|
scsi->backend = ref_get ( &srp->refcnt );
|
|
|
|
scsi->command = srp_command;
|
|
|
|
ref_put ( &srp->refcnt );
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_parse_root_path:
|
|
|
|
ref_put ( &srp->refcnt );
|
|
|
|
err_alloc:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Detach SRP device
|
|
|
|
*
|
|
|
|
* @v scsi SCSI device
|
|
|
|
*/
|
|
|
|
void srp_detach ( struct scsi_device *scsi ) {
|
|
|
|
struct srp_device *srp =
|
|
|
|
container_of ( scsi->backend, struct srp_device, refcnt );
|
|
|
|
|
|
|
|
/* Close socket */
|
2010-06-16 02:31:29 +02:00
|
|
|
intf_shutdown ( &srp->socket, 0 );
|
2009-07-17 23:11:42 +02:00
|
|
|
scsi->command = scsi_detached_command;
|
|
|
|
ref_put ( scsi->backend );
|
|
|
|
scsi->backend = NULL;
|
|
|
|
}
|