summaryrefslogtreecommitdiffstats
path: root/src/include/ipxe
diff options
context:
space:
mode:
authorMichael Brown2010-09-15 03:57:07 +0200
committerMichael Brown2010-09-15 04:16:24 +0200
commit508ff4d614006557b549a7d26ecfca9655064a75 (patch)
tree00f555cbe724686adb556ea1115bdd26a6317a12 /src/include/ipxe
parent[block] Replace gPXE block-device API with an iPXE asynchronous interface (diff)
downloadipxe-508ff4d614006557b549a7d26ecfca9655064a75.tar.gz
ipxe-508ff4d614006557b549a7d26ecfca9655064a75.tar.xz
ipxe-508ff4d614006557b549a7d26ecfca9655064a75.zip
[fc] Add support for Fibre Channel devices
Add support for Fibre Channel ports, peers, and upper-layer protocols, and for Fibre Channel extended link services. Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/include/ipxe')
-rw-r--r--src/include/ipxe/errfile.h2
-rw-r--r--src/include/ipxe/fc.h439
-rw-r--r--src/include/ipxe/fcels.h452
-rw-r--r--src/include/ipxe/xfer.h16
4 files changed, 909 insertions, 0 deletions
diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h
index d78f28229..d530d9029 100644
--- a/src/include/ipxe/errfile.h
+++ b/src/include/ipxe/errfile.h
@@ -184,6 +184,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_wpa_tkip ( ERRFILE_NET | 0x00280000 )
#define ERRFILE_wpa_ccmp ( ERRFILE_NET | 0x00290000 )
#define ERRFILE_eth_slow ( ERRFILE_NET | 0x002a0000 )
+#define ERRFILE_fc ( ERRFILE_NET | 0x002b0000 )
+#define ERRFILE_fcels ( ERRFILE_NET | 0x002c0000 )
#define ERRFILE_image ( ERRFILE_IMAGE | 0x00000000 )
#define ERRFILE_elf ( ERRFILE_IMAGE | 0x00010000 )
diff --git a/src/include/ipxe/fc.h b/src/include/ipxe/fc.h
new file mode 100644
index 000000000..5d73068f2
--- /dev/null
+++ b/src/include/ipxe/fc.h
@@ -0,0 +1,439 @@
+#ifndef _IPXE_FC_H
+#define _IPXE_FC_H
+
+/**
+ * @file
+ *
+ * Fibre Channel
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/list.h>
+#include <ipxe/tables.h>
+#include <ipxe/interface.h>
+#include <ipxe/retry.h>
+
+/******************************************************************************
+ *
+ * Fibre Channel Names and identifiers
+ *
+ ******************************************************************************
+ */
+
+/** A Fibre Channel name */
+struct fc_name {
+ uint8_t bytes[8];
+} __attribute__ (( packed ));
+
+/** Length of Fibre Channel name text */
+#define FC_NAME_STRLEN 23 /* "xx:xx:xx:xx:xx:xx:xx:xx" */
+
+/** A Fibre Channel port identifier */
+struct fc_port_id {
+ uint8_t bytes[3];
+} __attribute__ (( packed ));
+
+/** Length of Fibre Channel port identifier next */
+#define FC_PORT_ID_STRLEN 9 /* "xx.xx.xx" */
+
+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;
+extern struct fc_port_id fc_ptp_high_port_id;
+
+extern const char * fc_id_ntoa ( const struct fc_port_id *id );
+extern int fc_id_aton ( const char *id_text, struct fc_port_id *id );
+extern const char * fc_ntoa ( const struct fc_name *wwn );
+extern int fc_aton ( const char *wwn_text, struct fc_name *wwn );
+
+/******************************************************************************
+ *
+ * Fibre Channel link state
+ *
+ ******************************************************************************
+ */
+
+/** Delay between failed link-up attempts */
+#define FC_LINK_RETRY_DELAY ( 2 * TICKS_PER_SEC )
+
+/** A Fibre Channel link state nonitor */
+struct fc_link_state {
+ /** Retry timer */
+ struct retry_timer timer;
+ /** Link state */
+ int rc;
+ /** Examine link state
+ *
+ * @v link Fibre Channel link state monitor
+ */
+ void ( * examine ) ( struct fc_link_state *link );
+};
+
+/**
+ * Check Fibre Channel link state
+ *
+ * @v link Fibre Channel link state monitor
+ * @ret link_up Link is up
+ */
+static inline __attribute__ (( always_inline )) int
+fc_link_ok ( struct fc_link_state *link ) {
+ return ( link->rc == 0 );
+}
+
+/******************************************************************************
+ *
+ * Fibre Channel packet formats and exchanges
+ *
+ ******************************************************************************
+ */
+
+/** A Fibre Channel Frame Header */
+struct fc_frame_header {
+ /** Routing control
+ *
+ * This is the bitwise OR of one @c fc_r_ctl_routing value and
+ * one @c fc_r_ctl_info value.
+ */
+ uint8_t r_ctl;
+ /** Destination ID */
+ struct fc_port_id d_id;
+ /** Class-specific control / Priority */
+ uint8_t cs_ctl_prio;
+ /** Source ID */
+ struct fc_port_id s_id;
+ /** Data structure type */
+ uint8_t type;
+ /** Frame control - exchange and sequence */
+ uint8_t f_ctl_es;
+ /** Frame control - acknowledgements */
+ uint8_t f_ctl_ack;
+ /** Frame control - miscellaneous */
+ uint8_t f_ctl_misc;
+ /** Sequence ID */
+ uint8_t seq_id;
+ /** Data field control */
+ uint8_t df_ctl;
+ /** Sequence count */
+ uint16_t seq_cnt;
+ /** Originator exchange ID */
+ uint16_t ox_id;
+ /** Responder exchange ID */
+ uint16_t rx_id;
+ /** Parameter
+ *
+ * Contains the relative offset when @c FC_F_CTL_MISC_REL_OFF
+ * is set.
+ */
+ uint32_t parameter;
+} __attribute__ (( packed ));
+
+/** Fibre Channel Routing Control Routing */
+enum fc_r_ctl_routing {
+ FC_R_CTL_DATA = 0x00, /**< Device Data */
+ FC_R_CTL_ELS = 0x20, /**< Extended Link Services */
+ FC_R_CTL_FC4_LINK = 0x30, /**< FC-4 Link Data */
+ FC_R_CTL_VIDEO = 0x40, /**< Video Data */
+ FC_R_CTL_EH = 0x50, /**< Extended Headers */
+ FC_R_CTL_BLS = 0x80, /**< Basic Link Services */
+ FC_R_CTL_LINK_CTRL = 0xc0, /**< Link Control */
+ FC_R_CTL_EXT_ROUTE = 0xf0, /**< Extended Routing */
+};
+
+/** Fibre Channel Routing Control Routing mask */
+#define FC_R_CTL_ROUTING_MASK 0xf0
+
+/** Fibre Channel Routing Control Information */
+enum fc_r_ctl_info {
+ FC_R_CTL_UNCAT = 0x00, /**< Uncategorized */
+ FC_R_CTL_SOL_DATA = 0x01, /**< Solicited Data */
+ FC_R_CTL_UNSOL_CTRL = 0x02, /**< Unsolicited Control */
+ FC_R_CTL_SOL_CTRL = 0x03, /**< Solicited Control */
+ FC_R_CTL_UNSOL_DATA = 0x04, /**< Unsolicited Data */
+ FC_R_CTL_DATA_DESC = 0x05, /**< Data Descriptor */
+ FC_R_CTL_UNSOL_CMD = 0x06, /**< Unsolicited Command */
+ FC_R_CTL_CMD_STAT = 0x07, /**< Command Status */
+};
+
+/** Fibre Channel Routing Control Information mask */
+#define FC_R_CTL_INFO_MASK 0x07
+
+/** Fibre Channel Data Structure Type */
+enum fc_type {
+ FC_TYPE_BLS = 0x00, /**< Basic Link Service */
+ FC_TYPE_ELS = 0x01, /**< Extended Link Service */
+ FC_TYPE_FCP = 0x08, /**< Fibre Channel Protocol */
+};
+
+/** Fibre Channel Frame Control - Exchange and Sequence */
+enum fc_f_ctl_es {
+ FC_F_CTL_ES_RESPONDER = 0x80, /**< Responder of Exchange */
+ FC_F_CTL_ES_RECIPIENT = 0x40, /**< Sequence Recipient */
+ FC_F_CTL_ES_FIRST = 0x20, /**< First Sequence of Exchange */
+ FC_F_CTL_ES_LAST = 0x10, /**< Last Sequence of Exchange */
+ FC_F_CTL_ES_END = 0x08, /**< Last Data Frame of Sequence */
+ FC_F_CTL_ES_TRANSFER = 0x01, /**< Transfer Sequence Initiative */
+};
+
+/** Fibre Channel Frame Control - Miscellaneous */
+enum fc_f_ctl_misc {
+ FC_F_CTL_MISC_REL_OFF = 0x08, /**< Relative Offset Present */
+};
+
+/** Responder exchange identifier used before first response */
+#define FC_RX_ID_UNKNOWN 0xffff
+
+struct fc_port;
+
+extern int fc_xchg_originate ( struct interface *parent, struct fc_port *port,
+ struct fc_port_id *peer_port_id,
+ unsigned int type );
+
+/** A Fibre Channel responder */
+struct fc_responder {
+ /** Type */
+ unsigned int type;
+ /** Respond to exchange
+ *
+ * @v xchg Exchange interface
+ * @v port Fibre Channel port
+ * @v port_id Local port ID
+ * @v peer_port_id Peer port ID
+ * @ret rc Return status code
+ */
+ int ( * respond ) ( struct interface *xchg, struct fc_port *port,
+ struct fc_port_id *port_id,
+ struct fc_port_id *peer_port_id );
+};
+
+/** Fibre Channel responder table */
+#define FC_RESPONDERS __table ( struct fc_responder, "fc_responders" )
+
+/** Declare a Fibre Channel responder */
+#define __fc_responder __table_entry ( FC_RESPONDERS, 01 )
+
+/******************************************************************************
+ *
+ * Fibre Channel ports
+ *
+ ******************************************************************************
+ */
+
+/** A Fibre Channel port */
+struct fc_port {
+ /** Reference count */
+ struct refcnt refcnt;
+ /** List of all ports */
+ struct list_head list;
+ /** Name of this port */
+ char name[8];
+
+ /** Transport interface */
+ struct interface transport;
+ /** Node name */
+ struct fc_name node_wwn;
+ /** Port name */
+ struct fc_name port_wwn;
+ /** Local port ID */
+ struct fc_port_id port_id;
+ /** Flags */
+ unsigned int flags;
+
+ /** Link state monitor */
+ struct fc_link_state link;
+ /** FLOGI interface */
+ struct interface flogi;
+ /** Link node name */
+ struct fc_name link_node_wwn;
+ /** Link port name */
+ struct fc_name link_port_wwn;
+ /** Link port ID (for point-to-point links only) */
+ struct fc_port_id ptp_link_port_id;
+
+ /** List of active exchanges */
+ struct list_head xchgs;
+};
+
+/** Fibre Channel port flags */
+enum fc_port_flags {
+ /** Port is attached to a fabric */
+ FC_PORT_HAS_FABRIC = 0x0001,
+};
+
+/**
+ * Get reference to Fibre Channel port
+ *
+ * @v port Fibre Channel port
+ * @ret port Fibre Channel port
+ */
+static inline __attribute__ (( always_inline )) struct fc_port *
+fc_port_get ( struct fc_port *port ) {
+ ref_get ( &port->refcnt );
+ return port;
+}
+
+/**
+ * Drop reference to Fibre Channel port
+ *
+ * @v port Fibre Channel port
+ */
+static inline __attribute__ (( always_inline )) void
+fc_port_put ( struct fc_port *port ) {
+ ref_put ( &port->refcnt );
+}
+
+extern struct list_head fc_ports;
+
+extern int fc_port_login ( struct fc_port *port, struct fc_port_id *port_id,
+ const struct fc_name *link_node_wwn,
+ const struct fc_name *link_port_wwn,
+ int has_fabric );
+extern void fc_port_logout ( struct fc_port *port, int rc );
+extern int fc_port_open ( struct interface *transport,
+ const struct fc_name *node_wwn,
+ const struct fc_name *port_wwn );
+extern struct fc_port * fc_port_find ( const char *name );
+
+/******************************************************************************
+ *
+ * Fibre Channel peers
+ *
+ ******************************************************************************
+ */
+
+/** A Fibre Channel peer */
+struct fc_peer {
+ /** Reference count */
+ struct refcnt refcnt;
+ /** List of all peers */
+ struct list_head list;
+
+ /** Node name */
+ struct fc_name node_wwn;
+
+ /** Link state monitor */
+ struct fc_link_state link;
+ /** PLOGI interface */
+ struct interface plogi;
+ /** Fibre Channel port, if known */
+ struct fc_port *port;
+ /** Peer port ID, if known */
+ struct fc_port_id port_id;
+
+ /** List of upper-layer protocols */
+ struct list_head ulps;
+ /** Active usage count */
+ unsigned int usage;
+};
+
+/**
+ * Get reference to Fibre Channel peer
+ *
+ * @v peer Fibre Channel peer
+ * @ret peer Fibre Channel peer
+ */
+static inline __attribute__ (( always_inline )) struct fc_peer *
+fc_peer_get ( struct fc_peer *peer ) {
+ ref_get ( &peer->refcnt );
+ return peer;
+}
+
+/**
+ * Drop reference to Fibre Channel peer
+ *
+ * @v peer Fibre Channel peer
+ */
+static inline __attribute__ (( always_inline )) void
+fc_peer_put ( struct fc_peer *peer ) {
+ ref_put ( &peer->refcnt );
+}
+
+extern struct list_head fc_peers;
+
+extern struct fc_peer * fc_peer_get_wwn ( const struct fc_name *node_wwn );
+extern struct fc_peer *
+fc_peer_get_port_id ( struct fc_port *port,
+ const struct fc_port_id *peer_port_id );
+extern int fc_peer_login ( struct fc_peer *peer,
+ struct fc_port *port,
+ struct fc_port_id *port_id );
+extern void fc_peer_logout ( struct fc_peer *peer, int rc );
+
+/******************************************************************************
+ *
+ * Fibre Channel upper-layer protocols
+ *
+ ******************************************************************************
+ */
+
+/** A Fibre Channel upper-layer protocol */
+struct fc_ulp {
+ /** Reference count */
+ struct refcnt refcnt;
+ /** Fibre Channel peer */
+ struct fc_peer *peer;
+ /** List of upper-layer protocols */
+ struct list_head list;
+
+ /** Type */
+ unsigned int type;
+ /** Flags */
+ unsigned int flags;
+
+ /** Link state monitor */
+ struct fc_link_state link;
+ /** PRLI interface */
+ struct interface prli;
+ /** Service parameters, if any */
+ void *param;
+ /** Service parameter length */
+ size_t param_len;
+
+ /** Active usage count */
+ unsigned int usage;
+};
+
+/** Fibre Channel upper-layer protocol flags */
+enum fc_ulp_flags {
+ /** A login originated by us has succeeded */
+ FC_ULP_ORIGINATED_LOGIN_OK = 0x0001,
+};
+
+/**
+ * Get reference to Fibre Channel upper-layer protocol
+ *
+ * @v ulp Fibre Channel upper-layer protocol
+ * @ret ulp Fibre Channel upper-layer protocol
+ */
+static inline __attribute__ (( always_inline )) struct fc_ulp *
+fc_ulp_get ( struct fc_ulp *ulp ) {
+ ref_get ( &ulp->refcnt );
+ return ulp;
+}
+
+/**
+ * Drop reference to Fibre Channel upper-layer protocol
+ *
+ * @v ulp Fibre Channel upper-layer protocol
+ */
+static inline __attribute__ (( always_inline )) void
+fc_ulp_put ( struct fc_ulp *ulp ) {
+ ref_put ( &ulp->refcnt );
+}
+
+extern struct fc_ulp * fc_ulp_get_wwn_type ( const struct fc_name *node_wwn,
+ unsigned int type );
+extern struct fc_ulp *
+fc_ulp_get_port_id_type ( struct fc_port *port,
+ const struct fc_port_id *peer_port_id,
+ unsigned int type );
+extern void fc_ulp_increment ( struct fc_ulp *ulp );
+extern void fc_ulp_decrement ( struct fc_ulp *ulp );
+extern int fc_ulp_login ( struct fc_ulp *ulp, const void *param,
+ size_t param_len, int originated );
+extern void fc_ulp_logout ( struct fc_ulp *ulp, int rc );
+
+#endif /* _IPXE_FC_H */
diff --git a/src/include/ipxe/fcels.h b/src/include/ipxe/fcels.h
new file mode 100644
index 000000000..b35cb04c7
--- /dev/null
+++ b/src/include/ipxe/fcels.h
@@ -0,0 +1,452 @@
+#ifndef _IPXE_FCELS_H
+#define _IPXE_FCELS_H
+
+/**
+ * @file
+ *
+ * Fibre Channel Extended Link Services
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/fc.h>
+#include <ipxe/tables.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/list.h>
+#include <ipxe/process.h>
+#include <ipxe/interface.h>
+
+/** Fibre Channel ELS frame common parameters */
+struct fc_els_frame_common {
+ /** ELS command code */
+ uint8_t command;
+ /** Reserved */
+ uint8_t reserved[3];
+} __attribute__ (( packed ));
+
+/** Fibre Channel ELS command codes */
+enum fc_els_command_code {
+ FC_ELS_LS_RJT = 0x01, /**< Link Service Reject */
+ FC_ELS_LS_ACC = 0x02, /**< Link Service Accept */
+ FC_ELS_PLOGI = 0x03, /**< Port Login */
+ FC_ELS_FLOGI = 0x04, /**< Fabric Login */
+ FC_ELS_LOGO = 0x05, /**< Logout */
+ FC_ELS_RTV = 0x0e, /**< Read Timeout Value */
+ FC_ELS_PRLI = 0x20, /**< Process Login */
+ FC_ELS_PRLO = 0x21, /**< Process Logout */
+};
+
+/** A Fibre Channel LS_RJT frame */
+struct fc_ls_rjt_frame {
+ /** ELS command code */
+ uint8_t command;
+ /** Reserved */
+ uint8_t reserved[4];
+ /** Reason code */
+ uint8_t reason;
+ /** Reason code explanation */
+ uint8_t explanation;
+ /** Vendor unique */
+ uint8_t vendor;
+} __attribute__ (( packed ));
+
+/** Fibre Channel ELS rejection reason codes */
+enum fc_els_reject_reason {
+ /** Invalid ELS command code */
+ FC_ELS_RJT_INVALID_COMMAND = 0x01,
+ /** Logical error */
+ FC_ELS_RJT_ILLOGICAL = 0x03,
+ /** Logical busy */
+ FC_ELS_RJT_BUSY = 0x05,
+ /** Protocol error */
+ FC_ELS_RJT_PROTOCOL = 0x07,
+ /** Unable to perform command request */
+ FC_ELS_RJT_UNABLE = 0x09,
+ /** Command not supported */
+ FC_ELS_RJT_UNSUPPORTED = 0x0b,
+ /** Command already in progress */
+ FC_ELS_RJT_IN_PROGRESS = 0x0e,
+};
+
+/** Fibre Channel "common" service parameters */
+struct fc_login_common {
+ /** Login version */
+ uint16_t version;
+ /** Buffer-to-buffer credit */
+ uint16_t credit;
+ /** Flags */
+ uint16_t flags;
+ /** Receive size */
+ uint16_t mtu;
+ /** "Common"?! */
+ union {
+ struct {
+ /** Maximum number of concurrent sequences */
+ uint16_t max_seq;
+ /** Relative offset by info category */
+ uint16_t rel_offs;
+ } plogi;
+ struct {
+ /** Resource allocation timeout value */
+ uint32_t r_a_tov;
+ } flogi;
+ } u;
+ /** Error detection timeout value */
+ uint32_t e_d_tov;
+} __attribute__ (( packed ));
+
+/** Fibre Channel default login version */
+#define FC_LOGIN_VERSION 0x2020
+
+/** Fibre Channel default buffer-to-buffer credit */
+#define FC_LOGIN_DEFAULT_B2B 10
+
+/** Continuously increasing relative offset */
+#define FC_LOGIN_CONTINUOUS_OFFSET 0x8000
+
+/** Clean address */
+#define FC_LOGIN_CLEAN 0x8000
+
+/** Multiple N_Port_ID support */
+#define FC_LOGIN_MULTI_N 0x8000
+
+/** Random relative offset */
+#define FC_LOGIN_RANDOM_OFFSET 0x4000
+
+/** Virtual fabrics */
+#define FC_LOGIN_VIRTUAL 0x4000
+
+/** Vendor version level */
+#define FC_LOGIN_VENDOR 0x2000
+
+/** Multiple N_Port_ID support */
+#define FC_LOGIN_MULTI_F 0x2000
+
+/** Forwarder port */
+#define FC_LOGIN_F_PORT 0x1000
+
+/** Alternative credit management */
+#define FC_LOGIN_ALT_CREDIT 0x0800
+
+/** Name server session started */
+#define FC_LOGIN_NSS_STARTED 0x0800
+
+/** Begin name server session */
+#define FC_LOGIN_NSS_BEGIN 0x0400
+
+/** 1ns error detection timer resolution */
+#define FC_LOGIN_HIRES_E_D_TOV 0x0400
+
+/** Broadcast supported */
+#define FC_LOGIN_BROADCAST 0x0100
+
+/** Query buffer conditions */
+#define FC_LOGIN_QUERY_BUF 0x0040
+
+/** Security */
+#define FC_LOGIN_SECURITY 0x0020
+
+/** Clock sync primitive capable */
+#define FC_LOGIN_CLOCK_SYNC 0x0010
+
+/** Short R_T timeout */
+#define FC_LOGIN_SHORT_R_T_TOV 0x0008
+
+/** Dynamic half duplex */
+#define FC_LOGIN_DHD 0x0004
+
+/** Continuously increasing sequence count */
+#define FC_LOGIN_CONTINUOUS_SEQ 0x0002
+
+/** Payload */
+#define FC_LOGIN_PAYLOAD 0x0001
+
+/** Fibre Channel default MTU */
+#define FC_LOGIN_DEFAULT_MTU 1452
+
+/** Default maximum number of concurrent sequences */
+#define FC_LOGIN_DEFAULT_MAX_SEQ 255
+
+/** Default relative offset by info category */
+#define FC_LOGIN_DEFAULT_REL_OFFS 0x1f
+
+/** Default E_D timeout value */
+#define FC_LOGIN_DEFAULT_E_D_TOV 2000
+
+/** Fibre Channel class-specific login parameters */
+struct fc_login_class {
+ /** Flags */
+ uint16_t flags;
+ /** Initiator flags */
+ uint16_t init_flags;
+ /** Recipient flags */
+ uint16_t recip_flags;
+ /** Receive data field size */
+ uint16_t mtu;
+ /** Maximum number of concurrent sequences */
+ uint16_t max_seq;
+ /** End-to-end credit */
+ uint16_t credit;
+ /** Reserved */
+ uint8_t reserved0;
+ /** Maximum number of open sequences per exchange */
+ uint8_t max_seq_per_xchg;
+ /** Reserved */
+ uint8_t reserved1[2];
+} __attribute__ (( packed ));
+
+/** Class valid */
+#define FC_LOGIN_CLASS_VALID 0x8000
+
+/** Sequential delivery requested */
+#define FC_LOGIN_CLASS_SEQUENTIAL 0x0800
+
+/** A Fibre Channel FLOGI/PLOGI frame */
+struct fc_login_frame {
+ /** ELS command code */
+ uint8_t command;
+ /** Reserved */
+ uint8_t reserved[3];
+ /** Common service parameters */
+ struct fc_login_common common;
+ /** Port name */
+ struct fc_name port_wwn;
+ /** Node name */
+ struct fc_name node_wwn;
+ /** Class 1 service parameters */
+ struct fc_login_class class1;
+ /** Class 2 service parameters */
+ struct fc_login_class class2;
+ /** Class 3 service parameters */
+ struct fc_login_class class3;
+ /** Class 4 service parameters */
+ struct fc_login_class class4;
+ /** Vendor version level */
+ uint8_t vendor_version[16];
+} __attribute__ (( packed ));
+
+/** A Fibre Channel LOGO request frame */
+struct fc_logout_request_frame {
+ /** ELS command code */
+ uint8_t command;
+ /** Reserved */
+ uint8_t reserved[4];
+ /** Port ID */
+ struct fc_port_id port_id;
+ /** Port name */
+ struct fc_name port_wwn;
+} __attribute__ (( packed ));
+
+/** A Fibre Channel LOGO response frame */
+struct fc_logout_response_frame {
+ /** ELS command code */
+ uint8_t command;
+ /** Reserved */
+ uint8_t reserved[3];
+} __attribute__ (( packed ));
+
+/** A Fibre Channel PRLI service parameter page */
+struct fc_prli_page {
+ /** Type code */
+ uint8_t type;
+ /** Type code extension */
+ uint8_t type_ext;
+ /** Flags and response code */
+ uint16_t flags;
+ /** Reserved */
+ uint32_t reserved[2];
+} __attribute__ (( packed ));
+
+/** Establish image pair */
+#define FC_PRLI_ESTABLISH 0x2000
+
+/** Response code mask */
+#define FC_PRLI_RESPONSE_MASK 0x0f00
+
+/** Request was executed successfully */
+#define FC_PRLI_RESPONSE_SUCCESS 0x0100
+
+/** A Fibre Channel PRLI frame */
+struct fc_prli_frame {
+ /** ELS command code */
+ uint8_t command;
+ /** Page length */
+ uint8_t page_len;
+ /** Payload length */
+ uint16_t len;
+ /** Service parameter page */
+ struct fc_prli_page page;
+} __attribute__ (( packed ));
+
+/** A Fibre Channel RTV request frame */
+struct fc_rtv_request_frame {
+ /** ELS command code */
+ uint8_t command;
+ /** Reserved */
+ uint8_t reserved[3];
+} __attribute__ (( packed ));
+
+/** A Fibre Channel RTV response frame */
+struct fc_rtv_response_frame {
+ /** ELS command code */
+ uint8_t command;
+ /** Reserved */
+ uint8_t reserved0[3];
+ /** Resource allocation timeout value */
+ uint32_t r_a_tov;
+ /** Error detection timeout value */
+ uint32_t e_d_tov;
+ /** Timeout qualifier */
+ uint16_t flags;
+ /** Reserved */
+ uint16_t reserved1;
+} __attribute__ (( packed ));
+
+/** 1ns error detection timer resolution */
+#define FC_RTV_HIRES_E_D_TOV 0x0400
+
+/** Short R_T timeout */
+#define FC_RTV_SHORT_R_T_TOV 0x0008
+
+/** A Fibre Channel extended link services transaction */
+struct fc_els {
+ /** Reference count */
+ struct refcnt refcnt;
+ /** Job control interface */
+ struct interface job;
+ /** Fibre Channel exchange */
+ struct interface xchg;
+ /** Request sending process */
+ struct process process;
+
+ /** Fibre Channel port */
+ struct fc_port *port;
+ /** Local port ID */
+ struct fc_port_id port_id;
+ /** Peer port ID */
+ struct fc_port_id peer_port_id;
+ /** ELS handler, if known */
+ struct fc_els_handler *handler;
+ /** Flags */
+ unsigned int flags;
+};
+
+/** Fibre Channel extended link services transaction flags */
+enum fc_els_flags {
+ /** ELS transaction is a request */
+ FC_ELS_REQUEST = 0x0001,
+};
+
+/** A Fibre Channel extended link services handler */
+struct fc_els_handler {
+ /** Name */
+ const char *name;
+ /** Transmit ELS request frame
+ *
+ * @v els Fibre Channel ELS transaction
+ * @ret rc Return status code
+ */
+ int ( * tx_request ) ( struct fc_els *els );
+ /** Transmit ELS response 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 data ELS frame
+ * @v len Length of ELS frame
+ * @ret rc Return status code
+ */
+ int ( * rx_request ) ( struct fc_els *els, const void *data,
+ size_t len );
+ /** 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 data ELS frame
+ * @v len Length of ELS frame
+ * @ret rc Return status code
+ */
+ int ( * detect ) ( struct fc_els *els, const void *data, size_t len );
+};
+
+/** Fibre Channel ELS handler table */
+#define FC_ELS_HANDLERS __table ( struct fc_els_handler, "fc_els_handlers" )
+
+/** Declare a Fibre Channel ELS handler */
+#define __fc_els_handler __table_entry ( FC_ELS_HANDLERS, 01 )
+
+/** A Fibre Channel ELS PRLI descriptor */
+struct fc_els_prli_descriptor {
+ /** Upper-layer protocol type */
+ unsigned int type;
+ /** Service parameter length */
+ size_t param_len;
+ /** Fibre Channel ELS handler */
+ struct fc_els_handler *handler;
+};
+
+/** Fibre Channel ELS PRLI descriptor table */
+#define FC_ELS_PRLI_DESCRIPTORS \
+ __table ( struct fc_els_prli_descriptor, "fc_els_prli_descriptors" )
+
+/** Declare a Fibre Channel ELS PRLI descriptor */
+#define __fc_els_prli_descriptor __table_entry ( FC_ELS_PRLI_DESCRIPTORS, 01 )
+
+/**
+ * Check if Fibre Channel ELS transaction is a request
+ *
+ * @v els Fibre Channel ELS transaction
+ * @ret is_request ELS transaction is a request
+ */
+static inline int fc_els_is_request ( struct fc_els *els ) {
+ return ( els->flags & FC_ELS_REQUEST );
+}
+
+/**
+ * Calculate ELS command to transmit
+ *
+ * @v els Fibre Channel ELS transaction
+ * @v request_command Command for requests
+ * @v command Command to transmit
+ */
+static inline unsigned int fc_els_tx_command ( struct fc_els *els,
+ unsigned int request_command ) {
+ return ( fc_els_is_request ( els ) ? request_command : FC_ELS_LS_ACC );
+}
+
+extern int fc_els_tx ( struct fc_els *els, const void *data, size_t len );
+extern int fc_els_request ( struct interface *job, struct fc_port *port,
+ struct fc_port_id *peer_port_id,
+ struct fc_els_handler *handler );
+extern int fc_els_flogi ( struct interface *parent, struct fc_port *port );
+extern int fc_els_plogi ( struct interface *parent, struct fc_port *port,
+ struct fc_port_id *peer_port_id );
+extern int fc_els_logo ( struct interface *parent, struct fc_port *port,
+ struct fc_port_id *peer_port_id );
+extern int fc_els_prli ( struct interface *parent, struct fc_port *port,
+ struct fc_port_id *peer_port_id, unsigned int type );
+extern int fc_els_prli_tx ( struct fc_els *els,
+ struct fc_els_prli_descriptor *descriptor,
+ void *param );
+extern int fc_els_prli_rx ( struct fc_els *els,
+ struct fc_els_prli_descriptor *descriptor,
+ const void *data, size_t len );
+extern int fc_els_prli_detect ( struct fc_els *els __unused,
+ struct fc_els_prli_descriptor *descriptor,
+ const void *data, size_t len );
+
+#endif /* _IPXE_FCELS_H */
diff --git a/src/include/ipxe/xfer.h b/src/include/ipxe/xfer.h
index 0c0303279..1167e5cba 100644
--- a/src/include/ipxe/xfer.h
+++ b/src/include/ipxe/xfer.h
@@ -46,6 +46,22 @@ struct xfer_metadata {
/** Offset is absolute */
#define XFER_FL_ABS_OFFSET 0x0001
+/** Sender is relinquishing use of half-duplex channel */
+#define XFER_FL_OVER 0x0002
+
+/** This is the final data transfer */
+#define XFER_FL_OUT 0x0004
+
+/** Data content represents a command or status message
+ *
+ * The flag @c XFER_FL_RESPONSE is used to distinguish between a
+ * command message and a status message.
+ */
+#define XFER_FL_CMD_STAT 0x0008
+
+/** Data content is a response */
+#define XFER_FL_RESPONSE 0x0010
+
/* Data transfer interface operations */
extern int xfer_vredirect ( struct interface *intf, int type,