[fc] Support Fibre Channel ECHO
Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
parent
f5115f96f7
commit
90930be8fe
@ -34,6 +34,7 @@ enum fc_els_command_code {
|
|||||||
FC_ELS_FLOGI = 0x04, /**< Fabric Login */
|
FC_ELS_FLOGI = 0x04, /**< Fabric Login */
|
||||||
FC_ELS_LOGO = 0x05, /**< Logout */
|
FC_ELS_LOGO = 0x05, /**< Logout */
|
||||||
FC_ELS_RTV = 0x0e, /**< Read Timeout Value */
|
FC_ELS_RTV = 0x0e, /**< Read Timeout Value */
|
||||||
|
FC_ELS_ECHO = 0x10, /**< Echo */
|
||||||
FC_ELS_PRLI = 0x20, /**< Process Login */
|
FC_ELS_PRLI = 0x20, /**< Process Login */
|
||||||
FC_ELS_PRLO = 0x21, /**< Process Logout */
|
FC_ELS_PRLO = 0x21, /**< Process Logout */
|
||||||
};
|
};
|
||||||
@ -310,6 +311,14 @@ struct fc_rtv_response_frame {
|
|||||||
/** Short R_T timeout */
|
/** Short R_T timeout */
|
||||||
#define FC_RTV_SHORT_R_T_TOV 0x0008
|
#define FC_RTV_SHORT_R_T_TOV 0x0008
|
||||||
|
|
||||||
|
/** A Fibre Channel ECHO frame */
|
||||||
|
struct fc_echo_frame_header {
|
||||||
|
/** ELS command code */
|
||||||
|
uint8_t command;
|
||||||
|
/** Reserved */
|
||||||
|
uint8_t reserved[3];
|
||||||
|
} __attribute__ (( packed ));
|
||||||
|
|
||||||
/** A Fibre Channel extended link services transaction */
|
/** A Fibre Channel extended link services transaction */
|
||||||
struct fc_els {
|
struct fc_els {
|
||||||
/** Reference count */
|
/** Reference count */
|
||||||
@ -343,37 +352,21 @@ enum fc_els_flags {
|
|||||||
struct fc_els_handler {
|
struct fc_els_handler {
|
||||||
/** Name */
|
/** Name */
|
||||||
const char *name;
|
const char *name;
|
||||||
/** Transmit ELS request frame
|
/** Transmit ELS frame
|
||||||
*
|
*
|
||||||
* @v els Fibre Channel ELS transaction
|
* @v els Fibre Channel ELS transaction
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
int ( * tx_request ) ( struct fc_els *els );
|
int ( * tx ) ( struct fc_els *els );
|
||||||
/** Transmit ELS response frame
|
/** Receive ELS frame
|
||||||
*
|
|
||||||
* @v els Fibre Channel ELS transaction
|
|
||||||
* @ret rc Return status code
|
|
||||||
*/
|
|
||||||
int ( * tx_response ) ( struct fc_els *els );
|
|
||||||
/** Receive ELS request frame
|
|
||||||
*
|
*
|
||||||
* @v els Fibre Channel ELS transaction
|
* @v els Fibre Channel ELS transaction
|
||||||
* @v data ELS frame
|
* @v data ELS frame
|
||||||
* @v len Length of ELS frame
|
* @v len Length of ELS frame
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
int ( * rx_request ) ( struct fc_els *els, const void *data,
|
int ( * rx ) ( struct fc_els *els, void *data, size_t len );
|
||||||
size_t len );
|
/** Detect ELS frame
|
||||||
/** Receive ELS response frame
|
|
||||||
*
|
|
||||||
* @v els Fibre Channel ELS transaction
|
|
||||||
* @v data ELS frame
|
|
||||||
* @v len Length of ELS frame
|
|
||||||
* @ret rc Return status code
|
|
||||||
*/
|
|
||||||
int ( * rx_response ) ( struct fc_els *els, const void *data,
|
|
||||||
size_t len );
|
|
||||||
/** Detect ELS request frame
|
|
||||||
*
|
*
|
||||||
* @v els Fibre Channel ELS transaction
|
* @v els Fibre Channel ELS transaction
|
||||||
* @v data ELS frame
|
* @v data ELS frame
|
||||||
@ -444,7 +437,7 @@ extern int fc_els_prli_tx ( struct fc_els *els,
|
|||||||
void *param );
|
void *param );
|
||||||
extern int fc_els_prli_rx ( struct fc_els *els,
|
extern int fc_els_prli_rx ( struct fc_els *els,
|
||||||
struct fc_els_prli_descriptor *descriptor,
|
struct fc_els_prli_descriptor *descriptor,
|
||||||
const void *data, size_t len );
|
void *data, size_t len );
|
||||||
extern int fc_els_prli_detect ( struct fc_els *els __unused,
|
extern int fc_els_prli_detect ( struct fc_els *els __unused,
|
||||||
struct fc_els_prli_descriptor *descriptor,
|
struct fc_els_prli_descriptor *descriptor,
|
||||||
const void *data, size_t len );
|
const void *data, size_t len );
|
||||||
|
293
src/net/fcels.c
293
src/net/fcels.c
@ -158,7 +158,6 @@ static int fc_els_rx ( struct fc_els *els,
|
|||||||
struct sockaddr_fc *src = ( ( struct sockaddr_fc * ) meta->src );
|
struct sockaddr_fc *src = ( ( struct sockaddr_fc * ) meta->src );
|
||||||
struct sockaddr_fc *dest = ( ( struct sockaddr_fc * ) meta->dest );
|
struct sockaddr_fc *dest = ( ( struct sockaddr_fc * ) meta->dest );
|
||||||
size_t len = iob_len ( iobuf );
|
size_t len = iob_len ( iobuf );
|
||||||
int ( * rx ) ( struct fc_els *els, const void *data, size_t len );
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
@ -206,28 +205,13 @@ static int fc_els_rx ( struct fc_els *els,
|
|||||||
DBGC2_HDA ( els, 0, frame, len );
|
DBGC2_HDA ( els, 0, frame, len );
|
||||||
|
|
||||||
/* Handle received frame */
|
/* Handle received frame */
|
||||||
rx = ( fc_els_is_request ( els ) ?
|
if ( ( rc = els->handler->rx ( els, frame, len ) ) != 0 ) {
|
||||||
els->handler->rx_response : els->handler->rx_request );
|
|
||||||
if ( ( rc = rx ( els, frame, len ) ) != 0 ) {
|
|
||||||
DBGC ( els, FCELS_FMT " could not handle received frame: "
|
DBGC ( els, FCELS_FMT " could not handle received frame: "
|
||||||
"%s\n", FCELS_ARGS ( els ), strerror ( rc ) );
|
"%s\n", FCELS_ARGS ( els ), strerror ( rc ) );
|
||||||
DBGC_HDA ( els, 0, frame, len );
|
DBGC_HDA ( els, 0, frame, len );
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free I/O buffer. Do this before transmitting response to
|
|
||||||
* minimise memory consumption.
|
|
||||||
*/
|
|
||||||
free_iob ( iob_disown ( iobuf ) );
|
|
||||||
|
|
||||||
/* Transmit response if applicable */
|
|
||||||
if ( ( ! fc_els_is_request ( els ) ) &&
|
|
||||||
( ( rc = els->handler->tx_response ( els ) ) != 0 ) ) {
|
|
||||||
DBGC ( els, FCELS_FMT " could not transmit response: %s\n",
|
|
||||||
FCELS_ARGS ( els ), strerror ( rc ) );
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
/* Free I/O buffer */
|
/* Free I/O buffer */
|
||||||
free_iob ( iobuf );
|
free_iob ( iobuf );
|
||||||
@ -286,7 +270,7 @@ static void fc_els_step ( struct process *process ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Transmit request */
|
/* Transmit request */
|
||||||
if ( ( rc = els->handler->tx_request ( els ) ) != 0 ) {
|
if ( ( rc = els->handler->tx ( els ) ) != 0 ) {
|
||||||
DBGC ( els, FCELS_FMT " could not transmit request: %s\n",
|
DBGC ( els, FCELS_FMT " could not transmit request: %s\n",
|
||||||
FCELS_ARGS ( els ), strerror ( rc ) );
|
FCELS_ARGS ( els ), strerror ( rc ) );
|
||||||
fc_els_close ( els, rc );
|
fc_els_close ( els, rc );
|
||||||
@ -394,7 +378,7 @@ struct fc_responder fc_els_responder __fc_responder = {
|
|||||||
* @v els Fibre Channel ELS transaction
|
* @v els Fibre Channel ELS transaction
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int fc_els_unknown_tx_request ( struct fc_els *els __unused ) {
|
static int fc_els_unknown_tx ( struct fc_els *els __unused ) {
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,34 +401,26 @@ static int fc_els_unknown_tx_response ( struct fc_els *els ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receive unknown ELS request
|
* Receive unknown ELS
|
||||||
*
|
*
|
||||||
* @v els Fibre Channel ELS transaction
|
* @v els Fibre Channel ELS transaction
|
||||||
* @v data ELS frame
|
* @v data ELS frame
|
||||||
* @v len Length of ELS frame
|
* @v len Length of ELS frame
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int fc_els_unknown_rx_request ( struct fc_els *els, const void *data,
|
static int fc_els_unknown_rx ( struct fc_els *els, void *data, size_t len ) {
|
||||||
size_t len ) {
|
int rc;
|
||||||
|
|
||||||
DBGC ( els, FCELS_FMT ":\n", FCELS_ARGS ( els ) );
|
DBGC ( els, FCELS_FMT ":\n", FCELS_ARGS ( els ) );
|
||||||
DBGC_HDA ( els, 0, data, len );
|
DBGC_HDA ( els, 0, data, len );
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/* Transmit response, if applicable */
|
||||||
* Receive unknown ELS response
|
if ( ! fc_els_is_request ( els ) ) {
|
||||||
*
|
if ( ( rc = fc_els_unknown_tx_response ( els ) ) != 0 )
|
||||||
* @v els Fibre Channel ELS transaction
|
return rc;
|
||||||
* @v data ELS frame
|
}
|
||||||
* @v len Length of ELS frame
|
|
||||||
* @ret rc Return status code
|
return 0;
|
||||||
*/
|
|
||||||
static int fc_els_unknown_rx_response ( struct fc_els *els __unused,
|
|
||||||
const void *data __unused,
|
|
||||||
size_t len __unused ) {
|
|
||||||
assert ( 0 );
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -464,10 +440,8 @@ static int fc_els_unknown_detect ( struct fc_els *els __unused,
|
|||||||
/** Unknown ELS handler */
|
/** Unknown ELS handler */
|
||||||
struct fc_els_handler fc_els_unknown_handler __fc_els_handler = {
|
struct fc_els_handler fc_els_unknown_handler __fc_els_handler = {
|
||||||
.name = "UNKNOWN",
|
.name = "UNKNOWN",
|
||||||
.tx_request = fc_els_unknown_tx_request,
|
.tx = fc_els_unknown_tx,
|
||||||
.tx_response = fc_els_unknown_tx_response,
|
.rx = fc_els_unknown_rx,
|
||||||
.rx_request = fc_els_unknown_rx_request,
|
|
||||||
.rx_response = fc_els_unknown_rx_response,
|
|
||||||
.detect = fc_els_unknown_detect,
|
.detect = fc_els_unknown_detect,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -513,9 +487,8 @@ static int fc_els_flogi_tx ( struct fc_els *els ) {
|
|||||||
* @v len Length of ELS frame
|
* @v len Length of ELS frame
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int fc_els_flogi_rx ( struct fc_els *els, const void *data,
|
static int fc_els_flogi_rx ( struct fc_els *els, void *data, size_t len ) {
|
||||||
size_t len ) {
|
struct fc_login_frame *flogi = data;
|
||||||
const struct fc_login_frame *flogi = data;
|
|
||||||
int has_fabric;
|
int has_fabric;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@ -557,6 +530,12 @@ static int fc_els_flogi_rx ( struct fc_els *els, const void *data,
|
|||||||
sizeof ( els->peer_port_id ) );
|
sizeof ( els->peer_port_id ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Transmit response, if applicable */
|
||||||
|
if ( ! fc_els_is_request ( els ) ) {
|
||||||
|
if ( ( rc = fc_els_flogi_tx ( els ) ) != 0 )
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -582,10 +561,8 @@ static int fc_els_flogi_detect ( struct fc_els *els __unused, const void *data,
|
|||||||
/** FLOGI ELS handler */
|
/** FLOGI ELS handler */
|
||||||
struct fc_els_handler fc_els_flogi_handler __fc_els_handler = {
|
struct fc_els_handler fc_els_flogi_handler __fc_els_handler = {
|
||||||
.name = "FLOGI",
|
.name = "FLOGI",
|
||||||
.tx_request = fc_els_flogi_tx,
|
.tx = fc_els_flogi_tx,
|
||||||
.tx_response = fc_els_flogi_tx,
|
.rx = fc_els_flogi_rx,
|
||||||
.rx_request = fc_els_flogi_rx,
|
|
||||||
.rx_response = fc_els_flogi_rx,
|
|
||||||
.detect = fc_els_flogi_detect,
|
.detect = fc_els_flogi_detect,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -650,9 +627,8 @@ static int fc_els_plogi_tx ( struct fc_els *els ) {
|
|||||||
* @v len Length of ELS frame
|
* @v len Length of ELS frame
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int fc_els_plogi_rx ( struct fc_els *els, const void *data,
|
static int fc_els_plogi_rx ( struct fc_els *els, void *data, size_t len ) {
|
||||||
size_t len ) {
|
struct fc_login_frame *plogi = data;
|
||||||
const struct fc_login_frame *plogi = data;
|
|
||||||
struct fc_peer *peer;
|
struct fc_peer *peer;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@ -695,11 +671,18 @@ static int fc_els_plogi_rx ( struct fc_els *els, const void *data,
|
|||||||
goto err_login;
|
goto err_login;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Transmit response, if applicable */
|
||||||
|
if ( ! fc_els_is_request ( els ) ) {
|
||||||
|
if ( ( rc = fc_els_plogi_tx ( els ) ) != 0 )
|
||||||
|
goto err_plogi_tx;
|
||||||
|
}
|
||||||
|
|
||||||
/* Drop temporary reference to peer */
|
/* Drop temporary reference to peer */
|
||||||
fc_peer_put ( peer );
|
fc_peer_put ( peer );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_plogi_tx:
|
||||||
err_login:
|
err_login:
|
||||||
fc_peer_put ( peer );
|
fc_peer_put ( peer );
|
||||||
err_peer_get_wwn:
|
err_peer_get_wwn:
|
||||||
@ -729,10 +712,8 @@ static int fc_els_plogi_detect ( struct fc_els *els __unused, const void *data,
|
|||||||
/** PLOGI ELS handler */
|
/** PLOGI ELS handler */
|
||||||
struct fc_els_handler fc_els_plogi_handler __fc_els_handler = {
|
struct fc_els_handler fc_els_plogi_handler __fc_els_handler = {
|
||||||
.name = "PLOGI",
|
.name = "PLOGI",
|
||||||
.tx_request = fc_els_plogi_tx,
|
.tx = fc_els_plogi_tx,
|
||||||
.tx_response = fc_els_plogi_tx,
|
.rx = fc_els_plogi_rx,
|
||||||
.rx_request = fc_els_plogi_rx,
|
|
||||||
.rx_response = fc_els_plogi_rx,
|
|
||||||
.detect = fc_els_plogi_detect,
|
.detect = fc_els_plogi_detect,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -764,7 +745,7 @@ int fc_els_plogi ( struct interface *parent, struct fc_port *port,
|
|||||||
* @v els Fibre Channel ELS transaction
|
* @v els Fibre Channel ELS transaction
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int fc_els_logo_tx_request ( struct fc_els *els ) {
|
static int fc_els_logo_tx ( struct fc_els *els ) {
|
||||||
struct fc_logout_request_frame logo;
|
struct fc_logout_request_frame logo;
|
||||||
|
|
||||||
/* Construct LOGO */
|
/* Construct LOGO */
|
||||||
@ -802,7 +783,7 @@ static int fc_els_logo_tx_response ( struct fc_els *els ) {
|
|||||||
* @v port_id Peer port ID
|
* @v port_id Peer port ID
|
||||||
*/
|
*/
|
||||||
static void fc_els_logo_logout ( struct fc_els *els,
|
static void fc_els_logo_logout ( struct fc_els *els,
|
||||||
const struct fc_port_id *peer_port_id ) {
|
struct fc_port_id *peer_port_id ) {
|
||||||
struct fc_peer *peer;
|
struct fc_peer *peer;
|
||||||
|
|
||||||
if ( ( memcmp ( peer_port_id, &fc_f_port_id,
|
if ( ( memcmp ( peer_port_id, &fc_f_port_id,
|
||||||
@ -827,9 +808,10 @@ static void fc_els_logo_logout ( struct fc_els *els,
|
|||||||
* @v len Length of ELS frame
|
* @v len Length of ELS frame
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int fc_els_logo_rx_request ( struct fc_els *els, const void *data,
|
static int fc_els_logo_rx_request ( struct fc_els *els, void *data,
|
||||||
size_t len ) {
|
size_t len ) {
|
||||||
const struct fc_logout_request_frame *logo = data;
|
struct fc_logout_request_frame *logo = data;
|
||||||
|
int rc;
|
||||||
|
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
if ( len < sizeof ( *logo ) ) {
|
if ( len < sizeof ( *logo ) ) {
|
||||||
@ -845,6 +827,10 @@ static int fc_els_logo_rx_request ( struct fc_els *els, const void *data,
|
|||||||
/* Log out individual peer or whole port as applicable */
|
/* Log out individual peer or whole port as applicable */
|
||||||
fc_els_logo_logout ( els, &logo->port_id );
|
fc_els_logo_logout ( els, &logo->port_id );
|
||||||
|
|
||||||
|
/* Transmit repsonse */
|
||||||
|
if ( ( rc = fc_els_logo_tx_response ( els ) ) != 0 )
|
||||||
|
return rc;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -856,8 +842,7 @@ static int fc_els_logo_rx_request ( struct fc_els *els, const void *data,
|
|||||||
* @v len Length of ELS frame
|
* @v len Length of ELS frame
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int fc_els_logo_rx_response ( struct fc_els *els,
|
static int fc_els_logo_rx_response ( struct fc_els *els, void *data __unused,
|
||||||
const void *data __unused,
|
|
||||||
size_t len __unused ) {
|
size_t len __unused ) {
|
||||||
|
|
||||||
/* Log out individual peer or whole port as applicable */
|
/* Log out individual peer or whole port as applicable */
|
||||||
@ -866,6 +851,23 @@ static int fc_els_logo_rx_response ( struct fc_els *els,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive LOGO
|
||||||
|
*
|
||||||
|
* @v els Fibre Channel ELS transaction
|
||||||
|
* @v data ELS frame
|
||||||
|
* @v len Length of ELS frame
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
static int fc_els_logo_rx ( struct fc_els *els, void *data, size_t len ) {
|
||||||
|
|
||||||
|
if ( fc_els_is_request ( els ) ) {
|
||||||
|
return fc_els_logo_rx_response ( els, data, len );
|
||||||
|
} else {
|
||||||
|
return fc_els_logo_rx_request ( els, data, len );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect LOGO
|
* Detect LOGO
|
||||||
*
|
*
|
||||||
@ -888,10 +890,8 @@ static int fc_els_logo_detect ( struct fc_els *els __unused, const void *data,
|
|||||||
/** LOGO ELS handler */
|
/** LOGO ELS handler */
|
||||||
struct fc_els_handler fc_els_logo_handler __fc_els_handler = {
|
struct fc_els_handler fc_els_logo_handler __fc_els_handler = {
|
||||||
.name = "LOGO",
|
.name = "LOGO",
|
||||||
.tx_request = fc_els_logo_tx_request,
|
.tx = fc_els_logo_tx,
|
||||||
.tx_response = fc_els_logo_tx_response,
|
.rx = fc_els_logo_rx,
|
||||||
.rx_request = fc_els_logo_rx_request,
|
|
||||||
.rx_response = fc_els_logo_rx_response,
|
|
||||||
.detect = fc_els_logo_detect,
|
.detect = fc_els_logo_detect,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1000,8 +1000,8 @@ int fc_els_prli_tx ( struct fc_els *els,
|
|||||||
*/
|
*/
|
||||||
int fc_els_prli_rx ( struct fc_els *els,
|
int fc_els_prli_rx ( struct fc_els *els,
|
||||||
struct fc_els_prli_descriptor *descriptor,
|
struct fc_els_prli_descriptor *descriptor,
|
||||||
const void *data, size_t len ) {
|
void *data, size_t len ) {
|
||||||
const struct {
|
struct {
|
||||||
struct fc_prli_frame frame;
|
struct fc_prli_frame frame;
|
||||||
uint8_t param[descriptor->param_len];
|
uint8_t param[descriptor->param_len];
|
||||||
} __attribute__ (( packed )) *prli = data;
|
} __attribute__ (( packed )) *prli = data;
|
||||||
@ -1055,11 +1055,18 @@ int fc_els_prli_rx ( struct fc_els *els,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Transmit response, if applicable */
|
||||||
|
if ( ! fc_els_is_request ( els ) ) {
|
||||||
|
if ( ( rc = els->handler->tx ( els ) ) != 0 )
|
||||||
|
goto err_tx;
|
||||||
|
}
|
||||||
|
|
||||||
/* Drop temporary reference to ULP */
|
/* Drop temporary reference to ULP */
|
||||||
fc_ulp_put ( ulp );
|
fc_ulp_put ( ulp );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_tx:
|
||||||
err_login:
|
err_login:
|
||||||
err_link:
|
err_link:
|
||||||
fc_ulp_put ( ulp );
|
fc_ulp_put ( ulp );
|
||||||
@ -1148,20 +1155,25 @@ static int fc_els_rtv_tx_response ( struct fc_els *els ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receive RTV request
|
* Receive RTV
|
||||||
*
|
*
|
||||||
* @v els Fibre Channel ELS transaction
|
* @v els Fibre Channel ELS transaction
|
||||||
* @v data ELS frame
|
* @v data ELS frame
|
||||||
* @v len Length of ELS frame
|
* @v len Length of ELS frame
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int fc_els_rtv_rx_request ( struct fc_els *els,
|
static int fc_els_rtv_rx ( struct fc_els *els, void *data __unused,
|
||||||
const void *data __unused,
|
|
||||||
size_t len __unused ) {
|
size_t len __unused ) {
|
||||||
|
int rc;
|
||||||
|
|
||||||
DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
|
DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
|
||||||
|
|
||||||
/* Nothing to do */
|
/* Transmit response */
|
||||||
|
if ( ! fc_els_is_request ( els ) ) {
|
||||||
|
if ( ( rc = fc_els_rtv_tx_response ( els ) ) != 0 )
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1187,9 +1199,140 @@ static int fc_els_rtv_detect ( struct fc_els *els __unused, const void *data,
|
|||||||
/** RTV ELS handler */
|
/** RTV ELS handler */
|
||||||
struct fc_els_handler fc_els_rtv_handler __fc_els_handler = {
|
struct fc_els_handler fc_els_rtv_handler __fc_els_handler = {
|
||||||
.name = "RTV",
|
.name = "RTV",
|
||||||
.tx_request = fc_els_unknown_tx_request,
|
.tx = fc_els_unknown_tx,
|
||||||
.tx_response = fc_els_rtv_tx_response,
|
.rx = fc_els_rtv_rx,
|
||||||
.rx_request = fc_els_rtv_rx_request,
|
|
||||||
.rx_response = fc_els_unknown_rx_response,
|
|
||||||
.detect = fc_els_rtv_detect,
|
.detect = fc_els_rtv_detect,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* ECHO
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** ECHO request data */
|
||||||
|
struct fc_echo_request_frame {
|
||||||
|
/** ECHO frame header */
|
||||||
|
struct fc_echo_frame_header echo;
|
||||||
|
/** Magic marker */
|
||||||
|
uint32_t magic;
|
||||||
|
} __attribute__ (( packed ));
|
||||||
|
|
||||||
|
/** ECHO magic marker */
|
||||||
|
#define FC_ECHO_MAGIC 0x69505845
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transmit ECHO
|
||||||
|
*
|
||||||
|
* @v els Fibre Channel ELS transaction
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
static int fc_els_echo_tx ( struct fc_els *els ) {
|
||||||
|
struct fc_echo_request_frame echo;
|
||||||
|
|
||||||
|
/* Construct ECHO */
|
||||||
|
memset ( &echo, 0, sizeof ( echo ) );
|
||||||
|
echo.echo.command = FC_ELS_ECHO;
|
||||||
|
echo.magic = htonl ( FC_ECHO_MAGIC );
|
||||||
|
|
||||||
|
/* Transmit ECHO */
|
||||||
|
return fc_els_tx ( els, &echo, sizeof ( echo ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive ECHO request
|
||||||
|
*
|
||||||
|
* @v els Fibre Channel ELS transaction
|
||||||
|
* @v data ELS frame
|
||||||
|
* @v len Length of ELS frame
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
static int fc_els_echo_rx_request ( struct fc_els *els, void *data,
|
||||||
|
size_t len ) {
|
||||||
|
struct {
|
||||||
|
struct fc_echo_frame_header echo;
|
||||||
|
char payload[ len - sizeof ( struct fc_echo_frame_header ) ];
|
||||||
|
} *echo = data;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
|
||||||
|
|
||||||
|
/* Transmit response */
|
||||||
|
echo->echo.command = FC_ELS_LS_ACC;
|
||||||
|
if ( ( rc = fc_els_tx ( els, echo, sizeof ( *echo ) ) ) != 0 )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Nothing to do */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive ECHO response
|
||||||
|
*
|
||||||
|
* @v els Fibre Channel ELS transaction
|
||||||
|
* @v data ELS frame
|
||||||
|
* @v len Length of ELS frame
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
static int fc_els_echo_rx_response ( struct fc_els *els, void *data,
|
||||||
|
size_t len ) {
|
||||||
|
struct fc_echo_request_frame *echo = data;
|
||||||
|
|
||||||
|
DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
|
||||||
|
|
||||||
|
/* Check response is correct */
|
||||||
|
if ( ( len != sizeof ( *echo ) ) ||
|
||||||
|
( echo->magic != htonl ( FC_ECHO_MAGIC ) ) ) {
|
||||||
|
DBGC ( els, FCELS_FMT " received bad echo response\n",
|
||||||
|
FCELS_ARGS ( els ) );
|
||||||
|
DBGC_HDA ( els, 0, data, len );
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive ECHO
|
||||||
|
*
|
||||||
|
* @v els Fibre Channel ELS transaction
|
||||||
|
* @v data ELS frame
|
||||||
|
* @v len Length of ELS frame
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
static int fc_els_echo_rx ( struct fc_els *els, void *data, size_t len ) {
|
||||||
|
|
||||||
|
if ( fc_els_is_request ( els ) ) {
|
||||||
|
return fc_els_echo_rx_response ( els, data, len );
|
||||||
|
} else {
|
||||||
|
return fc_els_echo_rx_request ( els, data, len );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect ECHO
|
||||||
|
*
|
||||||
|
* @v els Fibre Channel ELS transaction
|
||||||
|
* @v data ELS frame
|
||||||
|
* @v len Length of ELS frame
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
static int fc_els_echo_detect ( struct fc_els *els __unused, const void *data,
|
||||||
|
size_t len __unused ) {
|
||||||
|
const struct fc_echo_frame_header *echo = data;
|
||||||
|
|
||||||
|
/* Check for ECHO */
|
||||||
|
if ( echo->command != FC_ELS_ECHO )
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ECHO ELS handler */
|
||||||
|
struct fc_els_handler fc_els_echo_handler __fc_els_handler = {
|
||||||
|
.name = "ECHO",
|
||||||
|
.tx = fc_els_echo_tx,
|
||||||
|
.rx = fc_els_echo_rx,
|
||||||
|
.detect = fc_els_echo_detect,
|
||||||
|
};
|
||||||
|
@ -103,7 +103,7 @@ static int fcp_prli_tx ( struct fc_els *els ) {
|
|||||||
* @v len Length of ELS frame
|
* @v len Length of ELS frame
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int fcp_prli_rx ( struct fc_els *els, const void *data, size_t len ) {
|
static int fcp_prli_rx ( struct fc_els *els, void *data, size_t len ) {
|
||||||
return fc_els_prli_rx ( els, &fcp_prli_descriptor, data, len );
|
return fc_els_prli_rx ( els, &fcp_prli_descriptor, data, len );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,10 +123,8 @@ static int fcp_prli_detect ( struct fc_els *els, const void *data,
|
|||||||
/** FCP PRLI ELS handler */
|
/** FCP PRLI ELS handler */
|
||||||
struct fc_els_handler fcp_prli_handler __fc_els_handler = {
|
struct fc_els_handler fcp_prli_handler __fc_els_handler = {
|
||||||
.name = "PRLI-FCP",
|
.name = "PRLI-FCP",
|
||||||
.tx_request = fcp_prli_tx,
|
.tx = fcp_prli_tx,
|
||||||
.tx_response = fcp_prli_tx,
|
.rx = fcp_prli_rx,
|
||||||
.rx_request = fcp_prli_rx,
|
|
||||||
.rx_response = fcp_prli_rx,
|
|
||||||
.detect = fcp_prli_detect,
|
.detect = fcp_prli_detect,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user