#include <ipxe/tables.h>
#include <ipxe/interface.h>
#include <ipxe/retry.h>
+#include <ipxe/socket.h>
/******************************************************************************
*
/** Length of Fibre Channel port identifier next */
#define FC_PORT_ID_STRLEN 9 /* "xx.xx.xx" */
+/**
+ * Fibre Channel socket address
+ */
+struct sockaddr_fc {
+ /** Socket address family (part of struct @c sockaddr)
+ *
+ * Always set to @c AF_FC for Fibre Channel addresses
+ */
+ sa_family_t sfc_family;
+ /** Port ID */
+ struct fc_port_id sfc_port_id;
+ /** Padding
+ *
+ * This ensures that a struct @c sockaddr_tcpip is large
+ * enough to hold a socket address for any TCP/IP address
+ * family.
+ */
+ char pad[ sizeof ( struct sockaddr ) - sizeof ( sa_family_t )
+ - sizeof ( struct fc_port_id ) ];
+} __attribute__ (( may_alias ));
+
extern struct fc_port_id fc_empty_port_id;
extern struct fc_port_id fc_f_port_id;
extern struct fc_port_id fc_ptp_low_port_id;
*/
#define AF_INET 1 /**< IPv4 Internet addresses */
#define AF_INET6 2 /**< IPv6 Internet addresses */
+#define AF_FC 3 /**< Fibre Channel addresses */
/** @} */
/**
static int fc_xchg_tx ( struct fc_exchange *xchg, struct io_buffer *iobuf,
struct xfer_metadata *meta ) {
struct fc_port *port = xchg->port;
+ struct sockaddr_fc *dest = ( ( struct sockaddr_fc * ) meta->dest );
struct fc_frame_header *fchdr;
unsigned int r_ctl;
unsigned int f_ctl_es;
fchdr = iob_push ( iobuf, sizeof ( *fchdr ) );
memset ( fchdr, 0, sizeof ( *fchdr ) );
fchdr->r_ctl = r_ctl;
- memcpy ( &fchdr->d_id, &xchg->peer_port_id, sizeof ( fchdr->d_id ) );
+ memcpy ( &fchdr->d_id,
+ ( dest ? &dest->sfc_port_id : &xchg->peer_port_id ),
+ sizeof ( fchdr->d_id ) );
memcpy ( &fchdr->s_id, &port->port_id, sizeof ( fchdr->s_id ) );
fchdr->type = xchg->type;
fchdr->f_ctl_es = f_ctl_es;
* @ret rc Return status code
*/
int fc_els_tx ( struct fc_els *els, const void *data, size_t len ) {
- struct xfer_metadata meta = {
- .flags = ( fc_els_is_request ( els ) ?
- XFER_FL_OVER : ( XFER_FL_RESPONSE | XFER_FL_OUT ) ),
- };
+ union {
+ struct sockaddr sa;
+ struct sockaddr_fc fc;
+ } dest;
+ struct xfer_metadata meta;
int rc;
DBGC2 ( els, FCELS_FMT " transmitting:\n", FCELS_ARGS ( els ) );
DBGC2_HDA ( els, 0, data, len );
+ /* Construct metadata */
+ memset ( &dest, 0, sizeof ( dest ) );
+ dest.fc.sfc_family = AF_FC;
+ memcpy ( &dest.fc.sfc_port_id, &els->peer_port_id,
+ sizeof ( dest.fc.sfc_port_id ) );
+ memset ( &meta, 0, sizeof ( meta ) );
+ meta.flags = ( fc_els_is_request ( els ) ?
+ XFER_FL_OVER : ( XFER_FL_RESPONSE | XFER_FL_OUT ) );
+ meta.dest = &dest.sa;
+
/* Transmit frame */
if ( ( rc = xfer_deliver_raw_meta ( &els->xchg, data, len,
&meta ) ) != 0 ) {
return rc;
}
+ /* Send any responses to the newly-assigned peer port ID, if
+ * applicable.
+ */
+ if ( ! has_fabric ) {
+ memcpy ( &els->peer_port_id, &els->port->ptp_link_port_id,
+ sizeof ( els->peer_port_id ) );
+ }
+
return 0;
}