mirror of https://github.com/ipxe/ipxe.git
539 lines
14 KiB
C
539 lines
14 KiB
C
#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>
|
|
#include <ipxe/socket.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" */
|
|
|
|
/**
|
|
* 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__ (( packed, 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_gs_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 );
|
|
extern struct sockaddr * fc_fill_sockaddr ( struct sockaddr_fc *sa_fc,
|
|
struct fc_port_id *id );
|
|
|
|
/******************************************************************************
|
|
*
|
|
* 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 */
|
|
FC_TYPE_CT = 0x20, /**< Common Transport */
|
|
};
|
|
|
|
/** 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;
|
|
|
|
/** Name server PLOGI interface */
|
|
struct interface ns_plogi;
|
|
|
|
/** 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,
|
|
/** Port is logged in to a name server */
|
|
FC_PORT_HAS_NS = 0x0002,
|
|
};
|
|
|
|
/**
|
|
* 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,
|
|
const char *name );
|
|
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;
|
|
|
|
/** Port name */
|
|
struct fc_name port_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
|
|
*
|
|
* A peer (and attached ULPs) may be created in response to
|
|
* unsolicited login requests received via the fabric. We
|
|
* track our own active usage count independently of the
|
|
* existence of the peer, so that if the peer becomes logged
|
|
* out (e.g. due to a link failure) then we know whether or
|
|
* not we should attempt to relogin.
|
|
*/
|
|
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 *port_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 users of this upper-layer protocol
|
|
*
|
|
* As with peers, an upper-layer protocol may be created in
|
|
* response to an unsolicited login request received via the
|
|
* fabric. This list records the number of active users of
|
|
* the ULP; the number of entries in the list is equivalent to
|
|
* the peer usage count.
|
|
*/
|
|
struct list_head users;
|
|
};
|
|
|
|
/** Fibre Channel upper-layer protocol flags */
|
|
enum fc_ulp_flags {
|
|
/** A login originated by us has succeeded */
|
|
FC_ULP_ORIGINATED_LOGIN_OK = 0x0001,
|
|
};
|
|
|
|
/** A Fibre Channel upper-layer protocol user */
|
|
struct fc_ulp_user {
|
|
/** Fibre Channel upper layer protocol */
|
|
struct fc_ulp *ulp;
|
|
/** List of users */
|
|
struct list_head list;
|
|
/** Containing object reference count, or NULL */
|
|
struct refcnt *refcnt;
|
|
/** Examine link state
|
|
*
|
|
* @v user Fibre Channel upper-layer-protocol user
|
|
*/
|
|
void ( * examine ) ( struct fc_ulp_user *user );
|
|
};
|
|
|
|
/**
|
|
* 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 );
|
|
}
|
|
|
|
/**
|
|
* Get reference to Fibre Channel upper-layer protocol user
|
|
*
|
|
* @v user Fibre Channel upper-layer protocol user
|
|
* @ret user Fibre Channel upper-layer protocol user
|
|
*/
|
|
static inline __attribute__ (( always_inline )) struct fc_ulp_user *
|
|
fc_ulp_user_get ( struct fc_ulp_user *user ) {
|
|
ref_get ( user->refcnt );
|
|
return user;
|
|
}
|
|
|
|
/**
|
|
* Drop reference to Fibre Channel upper-layer protocol user
|
|
*
|
|
* @v user Fibre Channel upper-layer protocol user
|
|
*/
|
|
static inline __attribute__ (( always_inline )) void
|
|
fc_ulp_user_put ( struct fc_ulp_user *user ) {
|
|
ref_put ( user->refcnt );
|
|
}
|
|
|
|
/**
|
|
* Initialise Fibre Channel upper-layer protocol user
|
|
*
|
|
* @v user Fibre Channel upper-layer protocol user
|
|
* @v examine Examine link state method
|
|
* @v refcnt Containing object reference count, or NULL
|
|
*/
|
|
static inline __attribute__ (( always_inline )) void
|
|
fc_ulp_user_init ( struct fc_ulp_user *user,
|
|
void ( * examine ) ( struct fc_ulp_user *user ),
|
|
struct refcnt *refcnt ) {
|
|
user->examine = examine;
|
|
user->refcnt = refcnt;
|
|
}
|
|
|
|
extern struct fc_ulp * fc_ulp_get_wwn_type ( const struct fc_name *port_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_attach ( struct fc_ulp *ulp, struct fc_ulp_user *user );
|
|
extern void fc_ulp_detach ( struct fc_ulp_user *user );
|
|
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 */
|