From 0f4fd09180bc85e3844c0e7b715edad02a8f18e1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 7 Oct 2010 16:21:56 +0100 Subject: [PATCH] [fcoe] Add support for the FCoE Initialization Protocol (FIP) Signed-off-by: Michael Brown --- src/include/ipxe/fcoe.h | 13 + src/include/ipxe/fip.h | 450 +++++++++++++++++++++++++ src/net/fcoe.c | 724 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 1141 insertions(+), 46 deletions(-) create mode 100644 src/include/ipxe/fip.h diff --git a/src/include/ipxe/fcoe.h b/src/include/ipxe/fcoe.h index 25723ec7..69120d3e 100644 --- a/src/include/ipxe/fcoe.h +++ b/src/include/ipxe/fcoe.h @@ -33,6 +33,19 @@ union fcoe_name { /** IEEE extended */ #define FCOE_AUTHORITY_IEEE_EXTENDED 0x2000 +/** An FCoE MAC address prefix (FC-MAP) */ +struct fcoe_map { + uint8_t bytes[3]; +} __attribute__ (( packed )); + +/** An FCoE (fabric-assigned) MAC address */ +struct fcoe_mac { + /** MAC address prefix */ + struct fcoe_map map; + /** Port ID */ + struct fc_port_id port_id; +} __attribute__ (( packed )); + /** An FCoE header */ struct fcoe_header { /** FCoE frame version */ diff --git a/src/include/ipxe/fip.h b/src/include/ipxe/fip.h new file mode 100644 index 00000000..b81e8604 --- /dev/null +++ b/src/include/ipxe/fip.h @@ -0,0 +1,450 @@ +#ifndef _IPXE_FIP_H +#define _IPXE_FIP_H + +/* + * Copyright (C) 2010 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +/** A FIP frame header */ +struct fip_header { + /** Frame version */ + uint8_t version; + /** Reserved */ + uint8_t reserved_a; + /** Protocol code */ + uint16_t code; + /** Reserved */ + uint8_t reserved_b; + /** Subcode */ + uint8_t subcode; + /** Descriptor list length in 32-bit words */ + uint16_t len; + /** Flags */ + uint16_t flags; +} __attribute__ (( packed )); + +/** FIP frame version */ +#define FIP_VERSION 0x10 + +/** FIP protocol code */ +enum fip_code { + FIP_CODE_DISCOVERY = 0x0001, /**< Discovery */ + FIP_CODE_ELS = 0x0002, /**< Extended link services */ + FIP_CODE_MAINTAIN = 0x0003, /**< Maintain virtual links */ + FIP_CODE_VLAN = 0x0004, /**< VLAN */ +}; + +/** FIP protocol subcode for discovery */ +enum fip_discovery_subcode { + FIP_DISCOVERY_SOLICIT = 0x01, /**< Discovery solicitation */ + FIP_DISCOVERY_ADVERTISE = 0x02, /**< Discovery advertisement */ +}; + +/** FIP protocol subcode for extended link services */ +enum fip_els_subcode { + FIP_ELS_REQUEST = 0x01, /**< ELS request */ + FIP_ELS_RESPONSE = 0x02, /**< ELS response */ +}; + +/** FIP protocol subcode for keep alive / clear links */ +enum fip_vitality_subcode { + FIP_MAINTAIN_KEEP_ALIVE = 0x01, /**< Keep alive */ + FIP_MAINTAIN_CLEAR_LINKS = 0x02,/**< Clear virtual links */ +}; + +/** FIP protocol subcode for VLAN */ +enum fip_vlan_subcode { + FIP_VLAN_REQUEST = 0x01, /**< VLAN request */ + FIP_VLAN_NOTIFY = 0x02, /**< VLAN notification */ +}; + +/** FIP flags */ +enum fip_flags { + FIP_FP = 0x8000, /**< Fabric-provided MAC address */ + FIP_SP = 0x4000, /**< Server-provided MAC address */ + FIP_A = 0x0004, /**< Available for login */ + FIP_S = 0x0002, /**< Solicited */ + FIP_F = 0x0001, /**< Forwarder */ +}; + +/** FIP descriptor common fields */ +struct fip_common { + /** Type */ + uint8_t type; + /** Length in 32-bit words */ + uint8_t len; + /** Reserved */ + uint8_t reserved[2]; +} __attribute__ (( packed )); + +/** FIP descriptor types */ +enum fip_type { + FIP_RESERVED = 0x00, /**< Reserved */ + FIP_PRIORITY = 0x01, /**< Priority */ + FIP_MAC_ADDRESS = 0x02, /**< MAC address */ + FIP_FC_MAP = 0x03, /**< FC-MAP */ + FIP_NAME_ID = 0x04, /**< Name identifier */ + FIP_FABRIC = 0x05, /**< Fabric */ + FIP_MAX_FCOE_SIZE = 0x06, /**< Max FCoE size */ + FIP_FLOGI = 0x07, /**< FLOGI */ + FIP_NPIV_FDISC = 0x08, /**< NPIV FDISC */ + FIP_LOGO = 0x09, /**< LOGO */ + FIP_ELP = 0x0a, /**< ELP */ + FIP_VX_PORT_ID = 0x0b, /**< Vx port identification */ + FIP_FKA_ADV_P = 0x0c, /**< FKA ADV period */ + FIP_VENDOR_ID = 0x0d, /**< Vendor ID */ + FIP_VLAN = 0x0e, /**< VLAN */ + FIP_NUM_DESCRIPTOR_TYPES +}; + +/** FIP descriptor type is critical */ +#define FIP_IS_CRITICAL( type ) ( (type) <= 0x7f ) + +/** A FIP priority descriptor */ +struct fip_priority { + /** Type */ + uint8_t type; + /** Length in 32-bit words */ + uint8_t len; + /** Reserved */ + uint8_t reserved; + /** Priority + * + * A higher value indicates a lower priority. + */ + uint8_t priority; +} __attribute__ (( packed )); + +/** Default FIP priority */ +#define FIP_DEFAULT_PRIORITY 128 + +/** Lowest FIP priority */ +#define FIP_LOWEST_PRIORITY 255 + +/** A FIP MAC address descriptor */ +struct fip_mac_address { + /** Type */ + uint8_t type; + /** Length in 32-bit words */ + uint8_t len; + /** MAC address */ + uint8_t mac[ETH_ALEN]; +} __attribute__ (( packed )); + +/** A FIP FC-MAP descriptor */ +struct fip_fc_map { + /** Type */ + uint8_t type; + /** Length in 32-bit words */ + uint8_t len; + /** Reserved */ + uint8_t reserved[3]; + /** FC-MAP */ + struct fcoe_map map; +} __attribute__ (( packed )); + +/** A FIP name identifier descriptor */ +struct fip_name_id { + /** Type */ + uint8_t type; + /** Length in 32-bit words */ + uint8_t len; + /** Reserved */ + uint8_t reserved[2]; + /** Name identifier */ + struct fc_name name; +} __attribute__ (( packed )); + +/** A FIP fabric descriptor */ +struct fip_fabric { + /** Type */ + uint8_t type; + /** Length in 32-bit words */ + uint8_t len; + /** Virtual Fabric ID, if any */ + uint16_t vf_id; + /** Reserved */ + uint8_t reserved; + /** FC-MAP */ + struct fcoe_map map; + /** Fabric name */ + struct fc_name name; +} __attribute__ (( packed )); + +/** A FIP max FCoE size descriptor */ +struct fip_max_fcoe_size { + /** Type */ + uint8_t type; + /** Length in 32-bit words */ + uint8_t len; + /** Maximum FCoE size */ + uint16_t mtu; +} __attribute__ (( packed )); + +/** A FIP descriptor containing an encapsulated ELS frame */ +struct fip_els { + /** Type */ + uint8_t type; + /** Length in 32-bit words */ + uint8_t len; + /** Reserved */ + uint8_t reserved[2]; + /** Fibre Channel frame header */ + struct fc_frame_header fc; + /** ELS frame */ + struct fc_els_frame_common els; +} __attribute__ (( packed )); + +/** A FIP descriptor containing an encapsulated login frame */ +struct fip_login { + /** Type */ + uint8_t type; + /** Length in 32-bit words */ + uint8_t len; + /** Reserved */ + uint8_t reserved[2]; + /** Fibre Channel frame header */ + struct fc_frame_header fc; + /** ELS frame */ + struct fc_login_frame els; +} __attribute__ (( packed )); + +/** A FIP descriptor containing an encapsulated LOGO request frame */ +struct fip_logo_request { + /** Type */ + uint8_t type; + /** Length in 32-bit words */ + uint8_t len; + /** Reserved */ + uint8_t reserved[2]; + /** Fibre Channel frame header */ + struct fc_frame_header fc; + /** ELS frame */ + struct fc_logout_request_frame els; +} __attribute__ (( packed )); + +/** A FIP descriptor containing an encapsulated LOGO response frame */ +struct fip_logo_response { + /** Type */ + uint8_t type; + /** Length in 32-bit words */ + uint8_t len; + /** Reserved */ + uint8_t reserved[2]; + /** Fibre Channel frame header */ + struct fc_frame_header fc; + /** ELS frame */ + struct fc_logout_response_frame els; +} __attribute__ (( packed )); + +/** A FIP descriptor containing an encapsulated ELP frame */ +struct fip_elp { + /** Type */ + uint8_t type; + /** Length in 32-bit words */ + uint8_t len; + /** Reserved */ + uint8_t reserved[2]; + /** Fibre Channel frame header */ + struct fc_frame_header fc; + /** ELS frame */ + struct fc_els_frame_common els; + /** Uninteresting content */ + uint32_t dull[25]; +} __attribute__ (( packed )); + +/** A FIP descriptor containing an encapsulated LS_RJT frame */ +struct fip_ls_rjt { + /** Type */ + uint8_t type; + /** Length in 32-bit words */ + uint8_t len; + /** Reserved */ + uint8_t reserved[2]; + /** Fibre Channel frame header */ + struct fc_frame_header fc; + /** ELS frame */ + struct fc_ls_rjt_frame els; +} __attribute__ (( packed )); + +/** A FIP Vx port identification descriptor */ +struct fip_vx_port_id { + /** Type */ + uint8_t type; + /** Length in 32-bit words */ + uint8_t len; + /** MAC address */ + uint8_t mac[ETH_ALEN]; + /** Reserved */ + uint8_t reserved; + /** Address identifier */ + struct fc_port_id id; + /** Port name */ + struct fc_name name; +} __attribute__ (( packed )); + +/** A FIP FKA ADV period descriptor */ +struct fip_fka_adv_p { + /** Type */ + uint8_t type; + /** Length in 32-bit words */ + uint8_t len; + /** Reserved */ + uint8_t reserved; + /** Flags */ + uint8_t flags; + /** Keep alive advertisement period in milliseconds */ + uint32_t period; +} __attribute__ (( packed )); + +/** FIP FKA ADV period flags */ +enum fip_fka_adv_p_flags { + FIP_NO_KEEPALIVE = 0x01, /**< Do not send keepalives */ +}; + +/** A FIP vendor ID descriptor */ +struct fip_vendor_id { + /** Type */ + uint8_t type; + /** Length in 32-bit words */ + uint8_t len; + /** Reserved */ + uint8_t reserved[2]; + /** Vendor ID */ + uint8_t vendor[8]; +} __attribute__ (( packed )); + +/** A FIP VLAN descriptor */ +struct fip_vlan { + /** Type */ + uint8_t type; + /** Length in 32-bit words */ + uint8_t len; + /** VLAN ID */ + uint16_t vlan; +} __attribute__ (( packed )); + +/** A FIP descriptor */ +union fip_descriptor { + /** Common fields */ + struct fip_common common; + /** Priority descriptor */ + struct fip_priority priority; + /** MAC address descriptor */ + struct fip_mac_address mac_address; + /** FC-MAP descriptor */ + struct fip_fc_map fc_map; + /** Name identifier descriptor */ + struct fip_name_id name_id; + /** Fabric descriptor */ + struct fip_fabric fabric; + /** Max FCoE size descriptor */ + struct fip_max_fcoe_size max_fcoe_size; + /** FLOGI descriptor */ + struct fip_els flogi; + /** FLOGI request descriptor */ + struct fip_login flogi_request; + /** FLOGI LS_ACC descriptor */ + struct fip_login flogi_ls_acc; + /** FLOGI LS_RJT descriptor */ + struct fip_ls_rjt flogi_ls_rjt; + /** NPIV FDISC descriptor */ + struct fip_els npiv_fdisc; + /** NPIV FDISC request descriptor */ + struct fip_login npiv_fdisc_request; + /** NPIV FDISC LS_ACC descriptor */ + struct fip_login npiv_fdisc_ls_acc; + /** NPIV FDISC LS_RJT descriptor */ + struct fip_ls_rjt npiv_fdisc_ls_rjt; + /** LOGO descriptor */ + struct fip_els logo; + /** LOGO request descriptor */ + struct fip_logo_request logo_request; + /** LOGO LS_ACC descriptor */ + struct fip_logo_response logo_ls_acc; + /** LOGO LS_RJT descriptor */ + struct fip_ls_rjt logo_ls_rjt; + /** ELS descriptor */ + struct fip_els elp; + /** ELP request descriptor */ + struct fip_elp elp_request; + /** ELP LS_ACC descriptor */ + struct fip_elp elp_ls_acc; + /** ELP LS_RJT descriptor */ + struct fip_ls_rjt elp_ls_rjt; + /** Vx port identification descriptor */ + struct fip_vx_port_id vx_port_id; + /** FKA ADV period descriptor */ + struct fip_fka_adv_p fka_adv_p; + /** Vendor ID descriptor */ + struct fip_vendor_id vendor_id; + /** VLAN descriptor */ + struct fip_vlan vlan; +} __attribute__ (( packed )); + +/** A FIP descriptor set */ +struct fip_descriptors { + /** Descriptors, indexed by type */ + union fip_descriptor *desc[FIP_NUM_DESCRIPTOR_TYPES]; +}; + +/** + * Define a function to extract a specific FIP descriptor type from a list + * + * @v type Descriptor type + * @v name Descriptor name + * @v finder Descriptor finder + */ +#define FIP_DESCRIPTOR( type, name ) \ + static inline __attribute__ (( always_inline )) \ + typeof ( ( ( union fip_descriptor * ) NULL )->name ) * \ + fip_ ## name ( struct fip_descriptors *descs ) { \ + return &(descs->desc[type]->name); \ + } +FIP_DESCRIPTOR ( FIP_PRIORITY, priority ); +FIP_DESCRIPTOR ( FIP_MAC_ADDRESS, mac_address ); +FIP_DESCRIPTOR ( FIP_FC_MAP, fc_map ); +FIP_DESCRIPTOR ( FIP_NAME_ID, name_id ); +FIP_DESCRIPTOR ( FIP_FABRIC, fabric ); +FIP_DESCRIPTOR ( FIP_MAX_FCOE_SIZE, max_fcoe_size ); +FIP_DESCRIPTOR ( FIP_FLOGI, flogi ); +FIP_DESCRIPTOR ( FIP_FLOGI, flogi_request ); +FIP_DESCRIPTOR ( FIP_FLOGI, flogi_ls_acc ); +FIP_DESCRIPTOR ( FIP_FLOGI, flogi_ls_rjt ); +FIP_DESCRIPTOR ( FIP_NPIV_FDISC, npiv_fdisc ); +FIP_DESCRIPTOR ( FIP_NPIV_FDISC, npiv_fdisc_request ); +FIP_DESCRIPTOR ( FIP_NPIV_FDISC, npiv_fdisc_ls_acc ); +FIP_DESCRIPTOR ( FIP_NPIV_FDISC, npiv_fdisc_ls_rjt ); +FIP_DESCRIPTOR ( FIP_LOGO, logo ); +FIP_DESCRIPTOR ( FIP_LOGO, logo_request ); +FIP_DESCRIPTOR ( FIP_LOGO, logo_ls_acc ); +FIP_DESCRIPTOR ( FIP_LOGO, logo_ls_rjt ); +FIP_DESCRIPTOR ( FIP_ELP, elp ); +FIP_DESCRIPTOR ( FIP_ELP, elp_request ); +FIP_DESCRIPTOR ( FIP_ELP, elp_ls_acc ); +FIP_DESCRIPTOR ( FIP_ELP, elp_ls_rjt ); +FIP_DESCRIPTOR ( FIP_VX_PORT_ID, vx_port_id ); +FIP_DESCRIPTOR ( FIP_FKA_ADV_P, fka_adv_p ); +FIP_DESCRIPTOR ( FIP_VENDOR_ID, vendor_id ); +FIP_DESCRIPTOR ( FIP_VLAN, vlan ); + +#endif /* _IPXE_FIP_H */ diff --git a/src/net/fcoe.c b/src/net/fcoe.c index 11acfca2..f22f9f7b 100644 --- a/src/net/fcoe.c +++ b/src/net/fcoe.c @@ -28,11 +28,15 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include #include #include +#include +#include #include +#include #include /** @file @@ -67,18 +71,75 @@ struct fcoe_port { struct interface transport; /** Network device */ struct net_device *netdev; + + /** Node WWN */ + union fcoe_name node_wwn; + /** Port WWN */ + union fcoe_name port_wwn; + + /** FIP retransmission timer */ + struct retry_timer timer; + /** FIP timeout counter */ + unsigned int timeouts; + /** Flags */ + unsigned int flags; + /** FCoE forwarder priority */ + unsigned int priority; + /** Keepalive delay (in ms) */ + unsigned int keepalive; /** FCoE forwarder MAC address */ - uint8_t fcf_ll_addr[ETH_ALEN]; + uint8_t fcf_mac[ETH_ALEN]; + /** Local MAC address */ + uint8_t local_mac[ETH_ALEN]; }; +/** FCoE flags */ +enum fcoe_flags { + /** Underlying network device is available */ + FCOE_HAVE_NETWORK = 0x0001, + /** We have selected an FCoE forwarder to use */ + FCOE_HAVE_FCF = 0x0002, + /** We have a FIP-capable FCoE forwarder available to be used */ + FCOE_HAVE_FIP_FCF = 0x0004, +}; + +struct net_protocol fcoe_protocol __net_protocol; +struct net_protocol fip_protocol __net_protocol; + +/** FCoE All-FCoE-MACs address */ +static uint8_t all_fcoe_macs[ETH_ALEN] = + { 0x01, 0x10, 0x18, 0x01, 0x00, 0x00 }; + +/** FCoE All-ENode-MACs address */ +static uint8_t all_enode_macs[ETH_ALEN] = + { 0x01, 0x10, 0x18, 0x01, 0x00, 0x01 }; + +/** FCoE All-FCF-MACs address */ +static uint8_t all_fcf_macs[ETH_ALEN] = + { 0x01, 0x10, 0x18, 0x01, 0x00, 0x02 }; + +/** Default FCoE forwarded MAC address */ +static uint8_t default_fcf_mac[ETH_ALEN] = + { 0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe }; + +/** Maximum number of FIP solicitations before giving up on FIP */ +#define FCOE_MAX_FIP_SOLICITATIONS 2 + +/** Delay between retrying FIP solicitations */ +#define FCOE_FIP_RETRY_DELAY ( TICKS_PER_SEC ) + +/** Maximum number of missing discovery advertisements */ +#define FCOE_MAX_FIP_MISSING_KEEPALIVES 4 + /** List of FCoE ports */ static LIST_HEAD ( fcoe_ports ); -struct net_protocol fcoe_protocol __net_protocol; - -/** Default FCoE forwarded MAC address */ -uint8_t fcoe_default_fcf_ll_addr[ETH_ALEN] = - { 0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe }; +/****************************************************************************** + * + * FCoE protocol + * + ****************************************************************************** + */ /** * Identify FCoE port by network device @@ -96,6 +157,37 @@ static struct fcoe_port * fcoe_demux ( struct net_device *netdev ) { return NULL; } +/** + * Reset FCoE port + * + * @v fcoe FCoE port + */ +static void fcoe_reset ( struct fcoe_port *fcoe ) { + + /* Reset any FIP state */ + stop_timer ( &fcoe->timer ); + fcoe->timeouts = 0; + fcoe->flags = 0; + fcoe->priority = ( FIP_LOWEST_PRIORITY + 1 ); + fcoe->keepalive = 0; + memcpy ( fcoe->fcf_mac, default_fcf_mac, + sizeof ( fcoe->fcf_mac ) ); + memcpy ( fcoe->local_mac, fcoe->netdev->ll_addr, + sizeof ( fcoe->local_mac ) ); + + /* Start FIP solicitation if network is available */ + if ( netdev_is_open ( fcoe->netdev ) && + netdev_link_ok ( fcoe->netdev ) ) { + fcoe->flags |= FCOE_HAVE_NETWORK; + start_timer_nodelay ( &fcoe->timer ); + DBGC ( fcoe, "FCoE %s starting FIP solicitation\n", + fcoe->netdev->name ); + } + + /* Send notification of window change */ + xfer_window_changed ( &fcoe->transport ); +} + /** * Transmit FCoE packet * @@ -108,28 +200,78 @@ static int fcoe_deliver ( struct fcoe_port *fcoe, struct io_buffer *iobuf, struct xfer_metadata *meta __unused ) { struct fc_frame_header *fchdr = iobuf->data; + struct fc_els_frame_common *els = ( iobuf->data + sizeof ( *fchdr ) ); struct fcoe_header *fcoehdr; struct fcoe_footer *fcoeftr; + struct fip_header *fiphdr; + struct fip_login *fipflogi; + struct fip_mac_address *fipmac; uint32_t crc; + struct net_protocol *net_protocol; + void *ll_source; int rc; - /* Calculate CRC */ - crc = crc32_le ( ~((uint32_t)0), iobuf->data, iob_len ( iobuf ) ); + /* Send as FIP or FCoE as appropriate */ + if ( ( fchdr->r_ctl == ( FC_R_CTL_ELS | FC_R_CTL_UNSOL_CTRL ) ) && + ( els->command == FC_ELS_FLOGI ) && + ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ) { - /* Create FCoE header */ - fcoehdr = iob_push ( iobuf, sizeof ( *fcoehdr ) ); - memset ( fcoehdr, 0, sizeof ( *fcoehdr ) ); - fcoehdr->sof = ( ( fchdr->seq_cnt == ntohs ( 0 ) ) ? - FCOE_SOF_I3 : FCOE_SOF_N3 ); - fcoeftr = iob_put ( iobuf, sizeof ( *fcoeftr ) ); - memset ( fcoeftr, 0, sizeof ( *fcoeftr ) ); - fcoeftr->crc = cpu_to_le32 ( crc ^ ~((uint32_t)0) ); - fcoeftr->eof = ( ( fchdr->f_ctl_es & FC_F_CTL_ES_END ) ? - FCOE_EOF_T : FCOE_EOF_N ); + /* Create FIP FLOGI descriptor */ + fipflogi = iob_push ( iobuf, + offsetof ( typeof ( *fipflogi ), fc ) ); + memset ( fipflogi, 0, offsetof ( typeof ( *fipflogi ), fc ) ); + fipflogi->type = FIP_FLOGI; + fipflogi->len = ( iob_len ( iobuf ) / 4 ); + + /* Create FIP MAC address descriptor */ + fipmac = iob_put ( iobuf, sizeof ( *fipmac ) ); + memset ( fipmac, 0, sizeof ( *fipmac ) ); + fipmac->type = FIP_MAC_ADDRESS; + fipmac->len = ( sizeof ( *fipmac ) / 4 ); + memcpy ( fipmac->mac, fcoe->netdev->ll_addr, + sizeof ( fipmac->mac ) ); + + /* Create FIP header */ + fiphdr = iob_push ( iobuf, sizeof ( *fiphdr ) ); + memset ( fiphdr, 0, sizeof ( *fiphdr ) ); + fiphdr->version = FIP_VERSION; + fiphdr->code = htons ( FIP_CODE_ELS ); + fiphdr->subcode = FIP_ELS_REQUEST; + fiphdr->len = + htons ( ( iob_len ( iobuf ) - sizeof ( *fiphdr ) ) / 4); + fiphdr->flags = htons ( FIP_FP | FIP_SP ); + + /* Send as FIP packet from netdev's own MAC address */ + net_protocol = &fip_protocol; + ll_source = fcoe->netdev->ll_addr; + + } else { + + /* Calculate CRC */ + crc = crc32_le ( ~((uint32_t)0), iobuf->data, + iob_len ( iobuf ) ); + + /* Create FCoE header */ + fcoehdr = iob_push ( iobuf, sizeof ( *fcoehdr ) ); + memset ( fcoehdr, 0, sizeof ( *fcoehdr ) ); + fcoehdr->sof = ( ( fchdr->seq_cnt == ntohs ( 0 ) ) ? + FCOE_SOF_I3 : FCOE_SOF_N3 ); + + /* Create FCoE footer */ + fcoeftr = iob_put ( iobuf, sizeof ( *fcoeftr ) ); + memset ( fcoeftr, 0, sizeof ( *fcoeftr ) ); + fcoeftr->crc = cpu_to_le32 ( crc ^ ~((uint32_t)0) ); + fcoeftr->eof = ( ( fchdr->f_ctl_es & FC_F_CTL_ES_END ) ? + FCOE_EOF_T : FCOE_EOF_N ); + + /* Send as FCoE packet from FCoE MAC address */ + net_protocol = &fcoe_protocol; + ll_source = fcoe->local_mac; + } /* Transmit packet */ - if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev, &fcoe_protocol, - fcoe->fcf_ll_addr, fcoe->netdev->ll_addr )) != 0){ + if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev, net_protocol, + fcoe->fcf_mac, ll_source ) ) != 0 ) { DBGC ( fcoe, "FCoE %s could not transmit: %s\n", fcoe->netdev->name, strerror ( rc ) ); goto done; @@ -169,7 +311,7 @@ static struct io_buffer * fcoe_alloc_iob ( struct fcoe_port *fcoe __unused, * @ret rc Return status code */ static int fcoe_rx ( struct io_buffer *iobuf, struct net_device *netdev, - const void *ll_dest __unused, const void *ll_source ) { + const void *ll_dest, const void *ll_source ) { struct fcoe_header *fcoehdr; struct fcoe_footer *fcoeftr; struct fcoe_port *fcoe; @@ -183,6 +325,17 @@ static int fcoe_rx ( struct io_buffer *iobuf, struct net_device *netdev, goto done; } + /* Discard packets not destined for us */ + if ( ( memcmp ( fcoe->local_mac, ll_dest, + sizeof ( fcoe->local_mac ) ) != 0 ) && + ( memcmp ( default_fcf_mac, ll_dest, + sizeof ( default_fcf_mac ) ) != 0 ) ) { + DBGC2 ( fcoe, "FCoE %s ignoring packet for %s\n", + fcoe->netdev->name, eth_ntoa ( ll_dest ) ); + rc = -ENOTCONN; + goto done; + } + /* Sanity check */ if ( iob_len ( iobuf ) < ( sizeof ( *fcoehdr ) + sizeof ( *fcoeftr ) )){ DBGC ( fcoe, "FCoE %s received under-length frame (%zd " @@ -226,8 +379,11 @@ static int fcoe_rx ( struct io_buffer *iobuf, struct net_device *netdev, goto done; } - /* Record FCF address */ - memcpy ( &fcoe->fcf_ll_addr, ll_source, sizeof ( fcoe->fcf_ll_addr ) ); + /* Record FCF address if applicable */ + if ( ( fcoe->flags & FCOE_HAVE_FCF ) && + ( ! ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ) ) { + memcpy ( &fcoe->fcf_mac, ll_source, sizeof ( fcoe->fcf_mac ) ); + } /* Hand off via transport interface */ if ( ( rc = xfer_deliver_iob ( &fcoe->transport, @@ -249,10 +405,7 @@ static int fcoe_rx ( struct io_buffer *iobuf, struct net_device *netdev, * @ret len Length of window */ static size_t fcoe_window ( struct fcoe_port *fcoe ) { - struct net_device *netdev = fcoe->netdev; - - return ( ( netdev_is_open ( netdev ) && netdev_link_ok ( netdev ) ) ? - ~( ( size_t ) 0 ) : 0 ); + return ( ( fcoe->flags & FCOE_HAVE_FCF ) ? ~( ( size_t ) 0 ) : 0 ); } /** @@ -263,6 +416,7 @@ static size_t fcoe_window ( struct fcoe_port *fcoe ) { */ static void fcoe_close ( struct fcoe_port *fcoe, int rc ) { + stop_timer ( &fcoe->timer ); intf_shutdown ( &fcoe->transport, rc ); netdev_put ( fcoe->netdev ); list_del ( &fcoe->list ); @@ -293,6 +447,483 @@ static struct interface_operation fcoe_transport_op[] = { static struct interface_descriptor fcoe_transport_desc = INTF_DESC ( struct fcoe_port, transport, fcoe_transport_op ); +/****************************************************************************** + * + * FIP protocol + * + ****************************************************************************** + */ + +/** + * Parse FIP packet into descriptor set + * + * @v fcoe FCoE port + * @v fiphdr FIP header + * @v len Length of FIP packet + * @v descs Descriptor set to fill in + * @ret rc Return status code + */ +static int fcoe_fip_parse ( struct fcoe_port *fcoe, struct fip_header *fiphdr, + size_t len, struct fip_descriptors *descs ) { + union fip_descriptor *desc; + size_t descs_len; + size_t desc_len; + size_t desc_offset; + unsigned int desc_type; + + /* Check FIP version */ + if ( fiphdr->version != FIP_VERSION ) { + DBGC ( fcoe, "FCoE %s received unsupported FIP version %02x\n", + fcoe->netdev->name, fiphdr->version ); + return -EINVAL; + } + + /* Check length */ + descs_len = ( ntohs ( fiphdr->len ) * 4 ); + if ( ( sizeof ( *fiphdr ) + descs_len ) > len ) { + DBGC ( fcoe, "FCoE %s received bad descriptor list length\n", + fcoe->netdev->name ); + return -EINVAL; + } + + /* Parse descriptor list */ + memset ( descs, 0, sizeof ( *descs ) ); + for ( desc_offset = 0 ; + desc_offset <= ( descs_len - sizeof ( desc->common ) ) ; + desc_offset += desc_len ) { + + /* Find descriptor and validate length */ + desc = ( ( ( void * ) ( fiphdr + 1 ) ) + desc_offset ); + desc_type = desc->common.type; + desc_len = ( desc->common.len * 4 ); + if ( desc_len == 0 ) { + DBGC ( fcoe, "FCoE %s received zero-length " + "descriptor\n", fcoe->netdev->name ); + return -EINVAL; + } + if ( ( desc_offset + desc_len ) > descs_len ) { + DBGC ( fcoe, "FCoE %s descriptor overrun\n", + fcoe->netdev->name ); + return -EINVAL; + } + + /* Handle descriptors that we understand */ + if ( ( desc_type > FIP_RESERVED ) && + ( desc_type < FIP_NUM_DESCRIPTOR_TYPES ) ) { + descs->desc[desc_type] = desc; + continue; + } + + /* Abort if we cannot understand a critical descriptor */ + if ( FIP_IS_CRITICAL ( desc_type ) ) { + DBGC ( fcoe, "FCoE %s cannot understand critical " + "descriptor type %02x\n", + fcoe->netdev->name, desc_type ); + return -ENOTSUP; + } + + /* Ignore non-critical descriptors that we cannot understand */ + } + + return 0; +} + +/** + * Send FIP discovery solicitation + * + * @v fcoe FCoE port + * @ret rc Return status code + */ +static int fcoe_fip_tx_solicitation ( struct fcoe_port *fcoe ) { + struct io_buffer *iobuf; + struct { + struct fip_header hdr; + struct fip_mac_address mac_address; + struct fip_name_id name_id; + struct fip_max_fcoe_size max_fcoe_size; + } __attribute__ (( packed )) *solicitation; + int rc; + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *solicitation ) ); + if ( ! iobuf ) + return -ENOMEM; + iob_reserve ( iobuf, MAX_LL_HEADER_LEN ); + + /* Construct discovery solicitation */ + solicitation = iob_put ( iobuf, sizeof ( *solicitation ) ); + memset ( solicitation, 0, sizeof ( *solicitation ) ); + solicitation->hdr.version = FIP_VERSION; + solicitation->hdr.code = htons ( FIP_CODE_DISCOVERY ); + solicitation->hdr.subcode = FIP_DISCOVERY_SOLICIT; + solicitation->hdr.len = htons ( ( sizeof ( *solicitation ) - + sizeof ( solicitation->hdr ) ) / 4 ); + solicitation->hdr.flags = htons ( FIP_FP | FIP_SP ); + solicitation->mac_address.type = FIP_MAC_ADDRESS; + solicitation->mac_address.len = + ( sizeof ( solicitation->mac_address ) / 4 ); + memcpy ( solicitation->mac_address.mac, fcoe->netdev->ll_addr, + sizeof ( solicitation->mac_address.mac ) ); + solicitation->name_id.type = FIP_NAME_ID; + solicitation->name_id.len = ( sizeof ( solicitation->name_id ) / 4 ); + memcpy ( &solicitation->name_id.name, &fcoe->node_wwn.fc, + sizeof ( solicitation->name_id.name ) ); + solicitation->max_fcoe_size.type = FIP_MAX_FCOE_SIZE; + solicitation->max_fcoe_size.len = + ( sizeof ( solicitation->max_fcoe_size ) / 4 ); + solicitation->max_fcoe_size.mtu = + htons ( ETH_MAX_MTU - sizeof ( struct fcoe_header ) - + sizeof ( struct fcoe_footer ) ); + + /* Send discovery solicitation */ + if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev, + &fip_protocol, all_fcf_macs, + fcoe->netdev->ll_addr ) ) != 0 ) { + DBGC ( fcoe, "FCoE %s could not send discovery solicitation: " + "%s\n", fcoe->netdev->name, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Handle received FIP discovery advertisement + * + * @v fcoe FCoE port + * @v descs Descriptor list + * @v flags Flags + * @ret rc Return status code + */ +static int fcoe_fip_rx_advertisement ( struct fcoe_port *fcoe, + struct fip_descriptors *descs, + unsigned int flags ) { + struct fip_priority *priority = fip_priority ( descs ); + struct fip_mac_address *mac_address = fip_mac_address ( descs ); + struct fip_fka_adv_p *fka_adv_p = fip_fka_adv_p ( descs ); + + /* Sanity checks */ + if ( ! priority ) { + DBGC ( fcoe, "FCoE %s received advertisement missing " + "priority\n", fcoe->netdev->name ); + return -EINVAL; + } + if ( ! mac_address ) { + DBGC ( fcoe, "FCoE %s received advertisement missing MAC " + "address\n", fcoe->netdev->name ); + return -EINVAL; + } + if ( ! fka_adv_p ) { + DBGC ( fcoe, "FCoE %s received advertisement missing FKA ADV " + "period\n", fcoe->netdev->name ); + return -EINVAL; + } + + if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) { + + /* We are soliciting for an FCF. Store the highest + * (i.e. lowest-valued) priority solicited + * advertisement that we receive. + */ + if ( ( ( flags & ( FIP_A | FIP_S | FIP_F ) ) == + ( FIP_A | FIP_S | FIP_F ) ) && + ( priority->priority < fcoe->priority ) ) { + + fcoe->flags |= FCOE_HAVE_FIP_FCF; + fcoe->priority = priority->priority; + if ( fka_adv_p->flags & FIP_NO_KEEPALIVE ) { + fcoe->keepalive = 0; + } else { + fcoe->keepalive = ntohl ( fka_adv_p->period ); + } + memcpy ( fcoe->fcf_mac, mac_address->mac, + sizeof ( fcoe->fcf_mac ) ); + DBGC ( fcoe, "FCoE %s selected FCF %s (priority %d, ", + fcoe->netdev->name, eth_ntoa ( fcoe->fcf_mac ), + fcoe->priority ); + if ( fcoe->keepalive ) { + DBGC ( fcoe, "keepalive %dms)\n", + fcoe->keepalive ); + } else { + DBGC ( fcoe, "no keepalive)\n" ); + } + } + + } else if ( fcoe->flags & FCOE_HAVE_FIP_FCF ) { + + /* We are checking that the FCF remains alive. Reset + * the timeout counter if this is an advertisement + * from our forwarder. + */ + if ( memcmp ( fcoe->fcf_mac, mac_address->mac, + sizeof ( fcoe->fcf_mac ) ) == 0 ) { + fcoe->timeouts = 0; + } + + } else { + + /* We are operating in non-FIP mode and have received + * a FIP advertisement. Reset the link in order to + * attempt FIP. + */ + fcoe_reset ( fcoe ); + + } + + return 0; +} + +/** + * Handle received FIP ELS response + * + * @v fcoe FCoE port + * @v descs Descriptor list + * @v flags Flags + * @ret rc Return status code + */ +static int fcoe_fip_rx_els_response ( struct fcoe_port *fcoe, + struct fip_descriptors *descs, + unsigned int flags __unused ) { + struct fip_els *flogi = fip_flogi ( descs ); + struct fip_mac_address *mac_address = fip_mac_address ( descs ); + void *frame; + size_t frame_len; + int rc; + + /* Sanity checks */ + if ( ! flogi ) { + DBGC ( fcoe, "FCoE %s received ELS response missing FLOGI\n", + fcoe->netdev->name ); + return -EINVAL; + } + if ( ! mac_address ) { + DBGC ( fcoe, "FCoE %s received ELS response missing MAC " + "address\n", fcoe->netdev->name ); + return -EINVAL; + } + + /* Record local MAC address */ + memcpy ( fcoe->local_mac, mac_address->mac, sizeof ( fcoe->local_mac )); + + /* Hand off via transport interface */ + frame = &flogi->fc; + frame_len = ( ( flogi->len * 4 ) - offsetof ( typeof ( *flogi ), fc ) ); + if ( ( rc = xfer_deliver_raw ( &fcoe->transport, frame, + frame_len ) ) != 0 ) { + DBGC ( fcoe, "FCoE %s could not deliver FIP FLOGI frame: %s\n", + fcoe->netdev->name, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Send FIP keepalive + * + * @v fcoe FCoE port + * @ret rc Return status code + */ +static int fcoe_fip_tx_keepalive ( struct fcoe_port *fcoe ) { + struct io_buffer *iobuf; + struct { + struct fip_header hdr; + struct fip_mac_address mac_address; + } __attribute__ (( packed )) *keepalive; + int rc; + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *keepalive ) ); + if ( ! iobuf ) + return -ENOMEM; + iob_reserve ( iobuf, MAX_LL_HEADER_LEN ); + + /* Construct keepalive */ + keepalive = iob_put ( iobuf, sizeof ( *keepalive ) ); + memset ( keepalive, 0, sizeof ( *keepalive ) ); + keepalive->hdr.version = FIP_VERSION; + keepalive->hdr.code = htons ( FIP_CODE_MAINTAIN ); + keepalive->hdr.subcode = FIP_MAINTAIN_KEEP_ALIVE; + keepalive->hdr.len = htons ( ( sizeof ( *keepalive ) - + sizeof ( keepalive->hdr ) ) / 4 ); + keepalive->mac_address.type = FIP_MAC_ADDRESS; + keepalive->mac_address.len = + ( sizeof ( keepalive->mac_address ) / 4 ); + memcpy ( keepalive->mac_address.mac, fcoe->netdev->ll_addr, + sizeof ( keepalive->mac_address.mac ) ); + + /* Send keepalive */ + if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev, + &fip_protocol, fcoe->fcf_mac, + fcoe->netdev->ll_addr ) ) != 0 ) { + DBGC ( fcoe, "FCoE %s could not send keepalive: %s\n", + fcoe->netdev->name, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** A FIP handler */ +struct fip_handler { + /** Protocol code */ + uint16_t code; + /** Protocol subcode */ + uint8_t subcode; + /** + * Receive FIP packet + * + * @v fcoe FCoE port + * @v descs Descriptor list + * @v flags Flags + * @ret rc Return status code + */ + int ( * rx ) ( struct fcoe_port *fcoe, struct fip_descriptors *descs, + unsigned int flags ); +}; + +/** FIP handlers */ +static struct fip_handler fip_handlers[] = { + { FIP_CODE_DISCOVERY, FIP_DISCOVERY_ADVERTISE, + fcoe_fip_rx_advertisement }, + { FIP_CODE_ELS, FIP_ELS_RESPONSE, + fcoe_fip_rx_els_response }, +}; + +/** + * Process incoming FIP packets + * + * @v iobuf I/O buffer + * @v netdev Network device + * @v ll_dest Link-layer destination address + * @v ll_source Link-layer source address + * @ret rc Return status code + */ +static int fcoe_fip_rx ( struct io_buffer *iobuf, + struct net_device *netdev, + const void *ll_dest, + const void *ll_source __unused ) { + struct fip_header *fiphdr = iobuf->data; + struct fip_descriptors descs; + struct fip_handler *handler; + struct fcoe_port *fcoe; + unsigned int i; + int rc; + + /* Identify FCoE port */ + if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) { + DBG ( "FCoE received FIP frame for net device %s missing FCoE " + "port\n", netdev->name ); + rc = -ENOTCONN; + goto done; + } + + /* Discard packets not destined for us */ + if ( ( memcmp ( fcoe->netdev->ll_addr, ll_dest, ETH_ALEN ) != 0 ) && + ( memcmp ( all_fcoe_macs, ll_dest, + sizeof ( all_fcoe_macs ) ) != 0 ) && + ( memcmp ( all_enode_macs, ll_dest, + sizeof ( all_enode_macs ) ) != 0 ) ) { + DBGC2 ( fcoe, "FCoE %s ignoring FIP packet for %s\n", + fcoe->netdev->name, eth_ntoa ( ll_dest ) ); + rc = -ENOTCONN; + goto done; + } + + /* Parse FIP packet */ + if ( ( rc = fcoe_fip_parse ( fcoe, fiphdr, iob_len ( iobuf ), + &descs ) ) != 0 ) + goto done; + + /* Find a suitable handler */ + for ( i = 0 ; i < ( sizeof ( fip_handlers ) / + sizeof ( fip_handlers[0] ) ) ; i++ ) { + handler = &fip_handlers[i]; + if ( ( handler->code == ntohs ( fiphdr->code ) ) && + ( handler->subcode == fiphdr->subcode ) ) { + rc = handler->rx ( fcoe, &descs, + ntohs ( fiphdr->flags ) ); + goto done; + } + } + DBGC ( fcoe, "FCoE %s received unsupported FIP code %04x.%02x\n", + fcoe->netdev->name, ntohs ( fiphdr->code ), fiphdr->subcode ); + rc = -ENOTSUP; + + done: + free_iob ( iobuf ); + return rc; +} + +/****************************************************************************** + * + * FCoE ports + * + ****************************************************************************** + */ + +/** + * Handle FCoE timer expiry + * + * @v timer FIP timer + * @v over Timer expired + */ +static void fcoe_expired ( struct retry_timer *timer, int over __unused ) { + struct fcoe_port *fcoe = + container_of ( timer, struct fcoe_port, timer ); + + /* Sanity check */ + assert ( fcoe->flags & FCOE_HAVE_NETWORK ); + + /* Increment the timeout counter */ + fcoe->timeouts++; + + if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) { + + /* If we have not yet found a FIP-capable forwarder, + * and we have not yet timed out and given up on + * finding one, then send a FIP solicitation and wait. + */ + if ( ( ! ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ) && + ( fcoe->timeouts <= FCOE_MAX_FIP_SOLICITATIONS ) ) { + start_timer_fixed ( &fcoe->timer, + FCOE_FIP_RETRY_DELAY ); + fcoe_fip_tx_solicitation ( fcoe ); + return; + } + + /* Either we have found a FIP-capable forwarder, or we + * have timed out and will fall back to pre-FIP mode. + */ + fcoe->flags |= FCOE_HAVE_FCF; + fcoe->timeouts = 0; + DBGC ( fcoe, "FCoE %s using %sFIP FCF %s\n", fcoe->netdev->name, + ( ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ? "" : "non-" ), + eth_ntoa ( fcoe->fcf_mac ) ); + + /* Start sending keepalives if applicable */ + if ( fcoe->keepalive ) + start_timer_nodelay ( &fcoe->timer ); + + /* Send notification of window change */ + xfer_window_changed ( &fcoe->transport ); + + } else { + + /* Send keepalive */ + start_timer_fixed ( &fcoe->timer, + ( ( fcoe->keepalive * TICKS_PER_SEC ) / 1000 ) ); + fcoe_fip_tx_keepalive ( fcoe ); + + /* Abandon FCF if we have not seen its advertisements */ + if ( fcoe->timeouts > FCOE_MAX_FIP_MISSING_KEEPALIVES ) { + DBGC ( fcoe, "FCoE %s abandoning FCF %s\n", + fcoe->netdev->name, eth_ntoa ( fcoe->fcf_mac )); + fcoe_reset ( fcoe ); + } + } +} + /** * Create FCoE port * @@ -302,8 +933,6 @@ static struct interface_descriptor fcoe_transport_desc = static int fcoe_probe ( struct net_device *netdev ) { struct ll_protocol *ll_protocol = netdev->ll_protocol; struct fcoe_port *fcoe; - union fcoe_name node_wwn; - union fcoe_name port_wwn; int rc; /* Sanity check */ @@ -313,7 +942,6 @@ static int fcoe_probe ( struct net_device *netdev ) { rc = 0; goto err_non_ethernet; } - assert ( ll_protocol->ll_addr_len == sizeof ( fcoe->fcf_ll_addr ) ); /* Allocate and initialise structure */ fcoe = zalloc ( sizeof ( *fcoe ) ); @@ -323,27 +951,24 @@ static int fcoe_probe ( struct net_device *netdev ) { } ref_init ( &fcoe->refcnt, NULL ); intf_init ( &fcoe->transport, &fcoe_transport_desc, &fcoe->refcnt ); + timer_init ( &fcoe->timer, fcoe_expired, &fcoe->refcnt ); fcoe->netdev = netdev_get ( netdev ); /* Construct node and port names */ - node_wwn.fcoe.authority = htons ( FCOE_AUTHORITY_IEEE ); - memcpy ( &node_wwn.fcoe.mac, netdev->ll_addr, - sizeof ( node_wwn.fcoe.mac ) ); - port_wwn.fcoe.authority = htons ( FCOE_AUTHORITY_IEEE_EXTENDED ); - memcpy ( &port_wwn.fcoe.mac, netdev->ll_addr, - sizeof ( port_wwn.fcoe.mac ) ); - - /* Construct initial FCF address */ - memcpy ( &fcoe->fcf_ll_addr, &fcoe_default_fcf_ll_addr, - sizeof ( fcoe->fcf_ll_addr ) ); + fcoe->node_wwn.fcoe.authority = htons ( FCOE_AUTHORITY_IEEE ); + memcpy ( &fcoe->node_wwn.fcoe.mac, netdev->ll_addr, + sizeof ( fcoe->node_wwn.fcoe.mac ) ); + fcoe->port_wwn.fcoe.authority = htons ( FCOE_AUTHORITY_IEEE_EXTENDED ); + memcpy ( &fcoe->port_wwn.fcoe.mac, netdev->ll_addr, + sizeof ( fcoe->port_wwn.fcoe.mac ) ); DBGC ( fcoe, "FCoE %s is %s", fcoe->netdev->name, - fc_ntoa ( &node_wwn.fc ) ); - DBGC ( fcoe, " port %s\n", fc_ntoa ( &port_wwn.fc ) ); + fc_ntoa ( &fcoe->node_wwn.fc ) ); + DBGC ( fcoe, " port %s\n", fc_ntoa ( &fcoe->port_wwn.fc ) ); /* Attach Fibre Channel port */ - if ( ( rc = fc_port_open ( &fcoe->transport, &node_wwn.fc, - &port_wwn.fc ) ) != 0 ) + if ( ( rc = fc_port_open ( &fcoe->transport, &fcoe->node_wwn.fc, + &fcoe->port_wwn.fc ) ) != 0 ) goto err_fc_create; /* Transfer reference to port list */ @@ -372,8 +997,8 @@ static void fcoe_notify ( struct net_device *netdev ) { return; } - /* Send notification of potential window change */ - xfer_window_changed ( &fcoe->transport ); + /* Reset the FCoE link */ + fcoe_reset ( fcoe ); } /** @@ -410,6 +1035,13 @@ struct net_protocol fcoe_protocol __net_protocol = { .rx = fcoe_rx, }; +/** FIP protocol */ +struct net_protocol fip_protocol __net_protocol = { + .name = "FIP", + .net_proto = htons ( ETH_P_FIP ), + .rx = fcoe_fip_rx, +}; + /** Human-readable message for CRC errors * * It seems as though several drivers neglect to strip the Ethernet