| #ifndef _IPXE_FCELS_H |
| #define _IPXE_FCELS_H |
| |
| /** |
| * @file |
| * |
| * Fibre Channel Extended Link Services |
| * |
| */ |
| |
| FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); |
| FILE_SECBOOT ( PERMITTED ); |
| |
| #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_ECHO = 0x10, /**< Echo */ |
| 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 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 */ |
| 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 frame |
| * |
| * @v els Fibre Channel ELS transaction |
| * @ret rc Return status code |
| */ |
| int ( * tx ) ( struct fc_els *els ); |
| /** Receive ELS frame |
| * |
| * @v els Fibre Channel ELS transaction |
| * @v data ELS frame |
| * @v len Length of ELS frame |
| * @ret rc Return status code |
| */ |
| int ( * rx ) ( struct fc_els *els, void *data, size_t len ); |
| /** Detect ELS 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, |
| 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 */ |