iPXE
fcoe.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <stddef.h>
00027 #include <stdlib.h>
00028 #include <errno.h>
00029 #include <byteswap.h>
00030 #include <ipxe/if_ether.h>
00031 #include <ipxe/if_arp.h>
00032 #include <ipxe/iobuf.h>
00033 #include <ipxe/interface.h>
00034 #include <ipxe/xfer.h>
00035 #include <ipxe/netdevice.h>
00036 #include <ipxe/ethernet.h>
00037 #include <ipxe/vlan.h>
00038 #include <ipxe/features.h>
00039 #include <ipxe/errortab.h>
00040 #include <ipxe/device.h>
00041 #include <ipxe/crc32.h>
00042 #include <ipxe/retry.h>
00043 #include <ipxe/timer.h>
00044 #include <ipxe/fc.h>
00045 #include <ipxe/fip.h>
00046 #include <ipxe/fcoe.h>
00047 
00048 /** @file
00049  *
00050  * FCoE protocol
00051  *
00052  */
00053 
00054 FEATURE ( FEATURE_PROTOCOL, "FCoE", DHCP_EB_FEATURE_FCOE, 1 );
00055 
00056 /* Disambiguate the various error causes */
00057 #define EINVAL_UNDERLENGTH __einfo_error ( EINFO_EINVAL_UNDERLENGTH )
00058 #define EINFO_EINVAL_UNDERLENGTH \
00059         __einfo_uniqify ( EINFO_EINVAL, 0x01, "Underlength packet" )
00060 #define EINVAL_SOF __einfo_error ( EINFO_EINVAL_SOF )
00061 #define EINFO_EINVAL_SOF \
00062         __einfo_uniqify ( EINFO_EINVAL, 0x02, "Invalid SoF delimiter" )
00063 #define EINVAL_CRC __einfo_error ( EINFO_EINVAL_CRC )
00064 #define EINFO_EINVAL_CRC \
00065         __einfo_uniqify ( EINFO_EINVAL, 0x03, "Invalid CRC (not stripped?)" )
00066 #define EINVAL_EOF __einfo_error ( EINFO_EINVAL_EOF )
00067 #define EINFO_EINVAL_EOF \
00068         __einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid EoF delimiter" )
00069 
00070 /** An FCoE port */
00071 struct fcoe_port {
00072         /** Reference count */
00073         struct refcnt refcnt;
00074         /** List of FCoE ports */
00075         struct list_head list;
00076         /** Transport interface */
00077         struct interface transport;
00078         /** Network device */
00079         struct net_device *netdev;
00080 
00081         /** Node WWN */
00082         union fcoe_name node_wwn;
00083         /** Port WWN */
00084         union fcoe_name port_wwn;
00085 
00086         /** FIP retransmission timer */
00087         struct retry_timer timer;
00088         /** FIP timeout counter */
00089         unsigned int timeouts;
00090         /** Flags */
00091         unsigned int flags;
00092         /** FCoE forwarder priority */
00093         unsigned int priority;
00094         /** Keepalive delay (in ms) */
00095         unsigned int keepalive;
00096         /** FCoE forwarder MAC address */
00097         uint8_t fcf_mac[ETH_ALEN];
00098         /** Local MAC address */
00099         uint8_t local_mac[ETH_ALEN];
00100 };
00101 
00102 /** FCoE flags */
00103 enum fcoe_flags {
00104         /** Underlying network device is available */
00105         FCOE_HAVE_NETWORK = 0x0001,
00106         /** We have selected an FCoE forwarder to use */
00107         FCOE_HAVE_FCF = 0x0002,
00108         /** We have a FIP-capable FCoE forwarder available to be used */
00109         FCOE_HAVE_FIP_FCF = 0x0004,
00110         /** FCoE forwarder supports server-provided MAC addresses */
00111         FCOE_FCF_ALLOWS_SPMA = 0x0008,
00112         /** An alternative VLAN has been found */
00113         FCOE_VLAN_FOUND = 0x0010,
00114         /** VLAN discovery has timed out */
00115         FCOE_VLAN_TIMED_OUT = 0x0020,
00116 };
00117 
00118 struct net_protocol fcoe_protocol __net_protocol;
00119 struct net_protocol fip_protocol __net_protocol;
00120 
00121 /** FCoE All-FCoE-MACs address */
00122 static uint8_t all_fcoe_macs[ETH_ALEN] =
00123         { 0x01, 0x10, 0x18, 0x01, 0x00, 0x00 };
00124 
00125 /** FCoE All-ENode-MACs address */
00126 static uint8_t all_enode_macs[ETH_ALEN] =
00127         { 0x01, 0x10, 0x18, 0x01, 0x00, 0x01 };
00128 
00129 /** FCoE All-FCF-MACs address */
00130 static uint8_t all_fcf_macs[ETH_ALEN] =
00131         { 0x01, 0x10, 0x18, 0x01, 0x00, 0x02 };
00132 
00133 /** Default FCoE forwarded MAC address */
00134 static uint8_t default_fcf_mac[ETH_ALEN] =
00135         { 0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe };
00136 
00137 /** Maximum number of VLAN requests before giving up on VLAN discovery */
00138 #define FCOE_MAX_VLAN_REQUESTS 2
00139 
00140 /** Delay between retrying VLAN requests */
00141 #define FCOE_VLAN_RETRY_DELAY ( TICKS_PER_SEC )
00142 
00143 /** Delay between retrying polling VLAN requests */
00144 #define FCOE_VLAN_POLL_DELAY ( 30 * TICKS_PER_SEC )
00145 
00146 /** Maximum number of FIP solicitations before giving up on FIP */
00147 #define FCOE_MAX_FIP_SOLICITATIONS 2
00148 
00149 /** Delay between retrying FIP solicitations */
00150 #define FCOE_FIP_RETRY_DELAY ( TICKS_PER_SEC )
00151 
00152 /** Maximum number of missing discovery advertisements */
00153 #define FCOE_MAX_FIP_MISSING_KEEPALIVES 4
00154 
00155 /** List of FCoE ports */
00156 static LIST_HEAD ( fcoe_ports );
00157 
00158 /******************************************************************************
00159  *
00160  * FCoE protocol
00161  *
00162  ******************************************************************************
00163  */
00164 
00165 /**
00166  * Identify FCoE port by network device
00167  *
00168  * @v netdev            Network device
00169  * @ret fcoe            FCoE port, or NULL
00170  */
00171 static struct fcoe_port * fcoe_demux ( struct net_device *netdev ) {
00172         struct fcoe_port *fcoe;
00173 
00174         list_for_each_entry ( fcoe, &fcoe_ports, list ) {
00175                 if ( fcoe->netdev == netdev )
00176                         return fcoe;
00177         }
00178         return NULL;
00179 }
00180 
00181 /**
00182  * Reset FCoE port
00183  *
00184  * @v fcoe              FCoE port
00185  */
00186 static void fcoe_reset ( struct fcoe_port *fcoe ) {
00187 
00188         /* Detach FC port, if any */
00189         intf_restart ( &fcoe->transport, -ECANCELED );
00190 
00191         /* Reset any FIP state */
00192         stop_timer ( &fcoe->timer );
00193         fcoe->timeouts = 0;
00194         fcoe->flags = 0;
00195         fcoe->priority = ( FIP_LOWEST_PRIORITY + 1 );
00196         fcoe->keepalive = 0;
00197         memcpy ( fcoe->fcf_mac, default_fcf_mac,
00198                  sizeof ( fcoe->fcf_mac ) );
00199         memcpy ( fcoe->local_mac, fcoe->netdev->ll_addr,
00200                  sizeof ( fcoe->local_mac ) );
00201 
00202         /* Start FIP solicitation if network is available */
00203         if ( netdev_is_open ( fcoe->netdev ) &&
00204              netdev_link_ok ( fcoe->netdev ) ) {
00205                 fcoe->flags |= FCOE_HAVE_NETWORK;
00206                 start_timer_nodelay ( &fcoe->timer );
00207                 DBGC ( fcoe, "FCoE %s starting %s\n", fcoe->netdev->name,
00208                        ( vlan_can_be_trunk ( fcoe->netdev ) ?
00209                          "VLAN discovery" : "FIP solicitation" ) );
00210         }
00211 
00212         /* Send notification of window change */
00213         xfer_window_changed ( &fcoe->transport );
00214 }
00215 
00216 /**
00217  * Transmit FCoE packet
00218  *
00219  * @v fcoe              FCoE port
00220  * @v iobuf             I/O buffer
00221  * @v meta              Data transfer metadata
00222  * @ret rc              Return status code
00223  */
00224 static int fcoe_deliver ( struct fcoe_port *fcoe,
00225                           struct io_buffer *iobuf,
00226                           struct xfer_metadata *meta __unused ) {
00227         struct fc_frame_header *fchdr = iobuf->data;
00228         struct fc_els_frame_common *els = ( iobuf->data + sizeof ( *fchdr ) );
00229         struct fcoe_header *fcoehdr;
00230         struct fcoe_footer *fcoeftr;
00231         struct fip_header *fiphdr;
00232         struct fip_login *fipflogi;
00233         struct fip_mac_address *fipmac;
00234         uint32_t crc;
00235         struct net_protocol *net_protocol;
00236         void *ll_source;
00237         int rc;
00238 
00239         /* Send as FIP or FCoE as appropriate */
00240         if ( ( fchdr->r_ctl == ( FC_R_CTL_ELS | FC_R_CTL_UNSOL_CTRL ) ) &&
00241              ( els->command == FC_ELS_FLOGI ) &&
00242              ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ) {
00243 
00244                 /* Create FIP FLOGI descriptor */
00245                 fipflogi = iob_push ( iobuf,
00246                                       offsetof ( typeof ( *fipflogi ), fc ) );
00247                 memset ( fipflogi, 0, offsetof ( typeof ( *fipflogi ), fc ) );
00248                 fipflogi->type = FIP_FLOGI;
00249                 fipflogi->len = ( iob_len ( iobuf ) / 4 );
00250 
00251                 /* Create FIP MAC address descriptor */
00252                 fipmac = iob_put ( iobuf, sizeof ( *fipmac ) );
00253                 memset ( fipmac, 0, sizeof ( *fipmac ) );
00254                 fipmac->type = FIP_MAC_ADDRESS;
00255                 fipmac->len = ( sizeof ( *fipmac ) / 4 );
00256                 if ( fcoe->flags & FCOE_FCF_ALLOWS_SPMA ) {
00257                         memcpy ( fipmac->mac, fcoe->netdev->ll_addr,
00258                                  sizeof ( fipmac->mac ) );
00259                 }
00260 
00261                 /* Create FIP header */
00262                 fiphdr = iob_push ( iobuf, sizeof ( *fiphdr ) );
00263                 memset ( fiphdr, 0, sizeof ( *fiphdr ) );
00264                 fiphdr->version = FIP_VERSION;
00265                 fiphdr->code = htons ( FIP_CODE_ELS );
00266                 fiphdr->subcode = FIP_ELS_REQUEST;
00267                 fiphdr->len =
00268                         htons ( ( iob_len ( iobuf ) - sizeof ( *fiphdr ) ) / 4);
00269                 fiphdr->flags = ( ( fcoe->flags & FCOE_FCF_ALLOWS_SPMA ) ?
00270                                   htons ( FIP_SP ) : htons ( FIP_FP ) );
00271 
00272                 /* Send as FIP packet from netdev's own MAC address */
00273                 net_protocol = &fip_protocol;
00274                 ll_source = fcoe->netdev->ll_addr;
00275 
00276         } else {
00277 
00278                 /* Calculate CRC */
00279                 crc = crc32_le ( ~((uint32_t)0), iobuf->data,
00280                                  iob_len ( iobuf ) );
00281 
00282                 /* Create FCoE header */
00283                 fcoehdr = iob_push ( iobuf, sizeof ( *fcoehdr ) );
00284                 memset ( fcoehdr, 0, sizeof ( *fcoehdr ) );
00285                 fcoehdr->sof = ( ( fchdr->seq_cnt == ntohs ( 0 ) ) ?
00286                                  FCOE_SOF_I3 : FCOE_SOF_N3 );
00287 
00288                 /* Create FCoE footer */
00289                 fcoeftr = iob_put ( iobuf, sizeof ( *fcoeftr ) );
00290                 memset ( fcoeftr, 0, sizeof ( *fcoeftr ) );
00291                 fcoeftr->crc = cpu_to_le32 ( crc ^ ~((uint32_t)0) );
00292                 fcoeftr->eof = ( ( fchdr->f_ctl_es & FC_F_CTL_ES_END ) ?
00293                                  FCOE_EOF_T : FCOE_EOF_N );
00294 
00295                 /* Send as FCoE packet from FCoE MAC address */
00296                 net_protocol = &fcoe_protocol;
00297                 ll_source = fcoe->local_mac;
00298         }
00299 
00300         /* Transmit packet */
00301         if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev, net_protocol,
00302                              fcoe->fcf_mac, ll_source ) ) != 0 ) {
00303                 DBGC ( fcoe, "FCoE %s could not transmit: %s\n",
00304                        fcoe->netdev->name, strerror ( rc ) );
00305                 goto done;
00306         }
00307 
00308  done:
00309         free_iob ( iobuf );
00310         return rc;
00311 }
00312 
00313 /**
00314  * Allocate FCoE I/O buffer
00315  *
00316  * @v len               Payload length
00317  * @ret iobuf           I/O buffer, or NULL
00318  */
00319 static struct io_buffer * fcoe_alloc_iob ( struct fcoe_port *fcoe __unused,
00320                                            size_t len ) {
00321         struct io_buffer *iobuf;
00322 
00323         iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( struct fcoe_header ) +
00324                             len + sizeof ( struct fcoe_footer ) );
00325         if ( iobuf ) {
00326                 iob_reserve ( iobuf, ( MAX_LL_HEADER_LEN +
00327                                        sizeof ( struct fcoe_header ) ) );
00328         }
00329         return iobuf;
00330 }
00331 
00332 /**
00333  * Process incoming FCoE packets
00334  *
00335  * @v iobuf             I/O buffer
00336  * @v netdev            Network device
00337  * @v ll_dest           Link-layer destination address
00338  * @v ll_source         Link-layer source address
00339  * @v flags             Packet flags
00340  * @ret rc              Return status code
00341  */
00342 static int fcoe_rx ( struct io_buffer *iobuf, struct net_device *netdev,
00343                      const void *ll_dest, const void *ll_source,
00344                      unsigned int flags __unused ) {
00345         struct fcoe_header *fcoehdr;
00346         struct fcoe_footer *fcoeftr;
00347         struct fcoe_port *fcoe;
00348         int rc;
00349 
00350         /* Identify FCoE port */
00351         if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) {
00352                 DBG ( "FCoE received frame for net device %s missing FCoE "
00353                       "port\n", netdev->name );
00354                 rc = -ENOTCONN;
00355                 goto done;
00356         }
00357 
00358         /* Discard packets not destined for us */
00359         if ( ( memcmp ( fcoe->local_mac, ll_dest,
00360                         sizeof ( fcoe->local_mac ) ) != 0 ) &&
00361              ( memcmp ( default_fcf_mac, ll_dest,
00362                         sizeof ( default_fcf_mac ) ) != 0 ) ) {
00363                 DBGC2 ( fcoe, "FCoE %s ignoring packet for %s\n",
00364                         fcoe->netdev->name, eth_ntoa ( ll_dest ) );
00365                 rc = -ENOTCONN;
00366                 goto done;
00367         }
00368 
00369         /* Sanity check */
00370         if ( iob_len ( iobuf ) < ( sizeof ( *fcoehdr ) + sizeof ( *fcoeftr ) )){
00371                 DBGC ( fcoe, "FCoE %s received under-length frame (%zd "
00372                        "bytes)\n", fcoe->netdev->name, iob_len ( iobuf ) );
00373                 rc = -EINVAL_UNDERLENGTH;
00374                 goto done;
00375         }
00376 
00377         /* Strip header and footer */
00378         fcoehdr = iobuf->data;
00379         iob_pull ( iobuf, sizeof ( *fcoehdr ) );
00380         fcoeftr = ( iobuf->data + iob_len ( iobuf ) - sizeof ( *fcoeftr ) );
00381         iob_unput ( iobuf, sizeof ( *fcoeftr ) );
00382 
00383         /* Validity checks */
00384         if ( fcoehdr->version != FCOE_FRAME_VER ) {
00385                 DBGC ( fcoe, "FCoE %s received unsupported frame version "
00386                        "%02x\n", fcoe->netdev->name, fcoehdr->version );
00387                 rc = -EPROTONOSUPPORT;
00388                 goto done;
00389         }
00390         if ( ! ( ( fcoehdr->sof == FCOE_SOF_I3 ) ||
00391                  ( fcoehdr->sof == FCOE_SOF_N3 ) ) ) {
00392                 DBGC ( fcoe, "FCoE %s received unsupported start-of-frame "
00393                        "delimiter %02x\n", fcoe->netdev->name, fcoehdr->sof );
00394                 rc = -EINVAL_SOF;
00395                 goto done;
00396         }
00397         if ( ( le32_to_cpu ( fcoeftr->crc ) ^ ~((uint32_t)0) ) !=
00398              crc32_le ( ~((uint32_t)0), iobuf->data, iob_len ( iobuf ) ) ) {
00399                 DBGC ( fcoe, "FCoE %s received invalid CRC\n",
00400                        fcoe->netdev->name );
00401                 rc = -EINVAL_CRC;
00402                 goto done;
00403         }
00404         if ( ! ( ( fcoeftr->eof == FCOE_EOF_N ) ||
00405                  ( fcoeftr->eof == FCOE_EOF_T ) ) ) {
00406                 DBGC ( fcoe, "FCoE %s received unsupported end-of-frame "
00407                        "delimiter %02x\n", fcoe->netdev->name, fcoeftr->eof );
00408                 rc = -EINVAL_EOF;
00409                 goto done;
00410         }
00411 
00412         /* Record FCF address if applicable */
00413         if ( ( fcoe->flags & FCOE_HAVE_FCF ) &&
00414              ( ! ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ) ) {
00415                 memcpy ( &fcoe->fcf_mac, ll_source, sizeof ( fcoe->fcf_mac ) );
00416         }
00417 
00418         /* Hand off via transport interface */
00419         if ( ( rc = xfer_deliver_iob ( &fcoe->transport,
00420                                        iob_disown ( iobuf ) ) ) != 0 ) {
00421                 DBGC ( fcoe, "FCoE %s could not deliver frame: %s\n",
00422                        fcoe->netdev->name, strerror ( rc ) );
00423                 goto done;
00424         }
00425 
00426  done:
00427         free_iob ( iobuf );
00428         return rc;
00429 }
00430 
00431 /**
00432  * Check FCoE flow control window
00433  *
00434  * @v fcoe              FCoE port
00435  * @ret len             Length of window
00436  */
00437 static size_t fcoe_window ( struct fcoe_port *fcoe ) {
00438         return ( ( fcoe->flags & FCOE_HAVE_FCF ) ? ~( ( size_t ) 0 ) : 0 );
00439 }
00440 
00441 /**
00442  * Close FCoE port
00443  *
00444  * @v fcoe              FCoE port
00445  * @v rc                Reason for close
00446  */
00447 static void fcoe_close ( struct fcoe_port *fcoe, int rc ) {
00448 
00449         stop_timer ( &fcoe->timer );
00450         intf_shutdown ( &fcoe->transport, rc );
00451         netdev_put ( fcoe->netdev );
00452         list_del ( &fcoe->list );
00453         ref_put ( &fcoe->refcnt );
00454 }
00455 
00456 /**
00457  * Identify device underlying FCoE port
00458  *
00459  * @v fcoe              FCoE port
00460  * @ret device          Underlying device
00461  */
00462 static struct device * fcoe_identify_device ( struct fcoe_port *fcoe ) {
00463         return fcoe->netdev->dev;
00464 }
00465 
00466 /** FCoE transport interface operations */
00467 static struct interface_operation fcoe_transport_op[] = {
00468         INTF_OP ( xfer_deliver, struct fcoe_port *, fcoe_deliver ),
00469         INTF_OP ( xfer_alloc_iob, struct fcoe_port *, fcoe_alloc_iob ),
00470         INTF_OP ( xfer_window, struct fcoe_port *, fcoe_window ),
00471         INTF_OP ( intf_close, struct fcoe_port *, fcoe_close ),
00472         INTF_OP ( identify_device, struct fcoe_port *,
00473                   fcoe_identify_device ),
00474 };
00475 
00476 /** FCoE transport interface descriptor */
00477 static struct interface_descriptor fcoe_transport_desc =
00478         INTF_DESC ( struct fcoe_port, transport, fcoe_transport_op );
00479 
00480 /******************************************************************************
00481  *
00482  * FIP protocol
00483  *
00484  ******************************************************************************
00485  */
00486 
00487 /**
00488  * Parse FIP packet into descriptor set
00489  *
00490  * @v fcoe              FCoE port
00491  * @v fiphdr            FIP header
00492  * @v len               Length of FIP packet
00493  * @v descs             Descriptor set to fill in
00494  * @ret rc              Return status code
00495  */
00496 static int fcoe_fip_parse ( struct fcoe_port *fcoe, struct fip_header *fiphdr,
00497                             size_t len, struct fip_descriptors *descs ) {
00498         union fip_descriptor *desc;
00499         size_t descs_len;
00500         size_t desc_len;
00501         size_t desc_offset;
00502         unsigned int desc_type;
00503 
00504         /* Check FIP version */
00505         if ( fiphdr->version != FIP_VERSION ) {
00506                 DBGC ( fcoe, "FCoE %s received unsupported FIP version %02x\n",
00507                        fcoe->netdev->name, fiphdr->version );
00508                 return -EINVAL;
00509         }
00510 
00511         /* Check length */
00512         descs_len = ( ntohs ( fiphdr->len ) * 4 );
00513         if ( ( sizeof ( *fiphdr ) + descs_len ) > len ) {
00514                 DBGC ( fcoe, "FCoE %s received bad descriptor list length\n",
00515                        fcoe->netdev->name );
00516                 return -EINVAL;
00517         }
00518 
00519         /* Parse descriptor list */
00520         memset ( descs, 0, sizeof ( *descs ) );
00521         for ( desc_offset = 0 ;
00522               desc_offset <= ( descs_len - sizeof ( desc->common ) ) ;
00523               desc_offset += desc_len ) {
00524 
00525                 /* Find descriptor and validate length */
00526                 desc = ( ( ( void * ) ( fiphdr + 1 ) ) + desc_offset );
00527                 desc_type = desc->common.type;
00528                 desc_len = ( desc->common.len * 4 );
00529                 if ( desc_len == 0 ) {
00530                         DBGC ( fcoe, "FCoE %s received zero-length "
00531                                "descriptor\n", fcoe->netdev->name );
00532                         return -EINVAL;
00533                 }
00534                 if ( ( desc_offset + desc_len ) > descs_len ) {
00535                         DBGC ( fcoe, "FCoE %s descriptor overrun\n",
00536                                fcoe->netdev->name );
00537                         return -EINVAL;
00538                 }
00539 
00540                 /* Handle descriptors that we understand */
00541                 if ( ( desc_type > FIP_RESERVED ) &&
00542                      ( desc_type < FIP_NUM_DESCRIPTOR_TYPES ) ) {
00543                         /* Use only the first instance of a descriptor */
00544                         if ( descs->desc[desc_type] == NULL )
00545                                 descs->desc[desc_type] = desc;
00546                         continue;
00547                 }
00548 
00549                 /* Abort if we cannot understand a critical descriptor */
00550                 if ( FIP_IS_CRITICAL ( desc_type ) ) {
00551                         DBGC ( fcoe, "FCoE %s cannot understand critical "
00552                                "descriptor type %02x\n",
00553                                fcoe->netdev->name, desc_type );
00554                         return -ENOTSUP;
00555                 }
00556 
00557                 /* Ignore non-critical descriptors that we cannot understand */
00558         }
00559 
00560         return 0;
00561 }
00562 
00563 /**
00564  * Send FIP VLAN request
00565  *
00566  * @v fcoe              FCoE port
00567  * @ret rc              Return status code
00568  */
00569 static int fcoe_fip_tx_vlan ( struct fcoe_port *fcoe ) {
00570         struct io_buffer *iobuf;
00571         struct {
00572                 struct fip_header hdr;
00573                 struct fip_mac_address mac_address;
00574         } __attribute__ (( packed )) *request;
00575         int rc;
00576 
00577         /* Allocate I/O buffer */
00578         iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *request ) );
00579         if ( ! iobuf )
00580                 return -ENOMEM;
00581         iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
00582 
00583         /* Construct VLAN request */
00584         request = iob_put ( iobuf, sizeof ( *request ) );
00585         memset ( request, 0, sizeof ( *request ) );
00586         request->hdr.version = FIP_VERSION;
00587         request->hdr.code = htons ( FIP_CODE_VLAN );
00588         request->hdr.subcode = FIP_VLAN_REQUEST;
00589         request->hdr.len = htons ( ( sizeof ( *request ) -
00590                                      sizeof ( request->hdr ) ) / 4 );
00591         request->mac_address.type = FIP_MAC_ADDRESS;
00592         request->mac_address.len =
00593                 ( sizeof ( request->mac_address ) / 4 );
00594         memcpy ( request->mac_address.mac, fcoe->netdev->ll_addr,
00595                  sizeof ( request->mac_address.mac ) );
00596 
00597         /* Send VLAN request */
00598         if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev,
00599                              &fip_protocol, all_fcf_macs,
00600                              fcoe->netdev->ll_addr ) ) != 0 ) {
00601                 DBGC ( fcoe, "FCoE %s could not send VLAN request: "
00602                        "%s\n", fcoe->netdev->name, strerror ( rc ) );
00603                 return rc;
00604         }
00605 
00606         return 0;
00607 }
00608 
00609 /**
00610  * Handle received FIP VLAN notification
00611  *
00612  * @v fcoe              FCoE port
00613  * @v descs             Descriptor list
00614  * @v flags             Flags
00615  * @ret rc              Return status code
00616  */
00617 static int fcoe_fip_rx_vlan ( struct fcoe_port *fcoe,
00618                               struct fip_descriptors *descs,
00619                               unsigned int flags __unused ) {
00620         struct fip_mac_address *mac_address = fip_mac_address ( descs );
00621         struct fip_vlan *vlan = fip_vlan ( descs );
00622         unsigned int tag;
00623         int rc;
00624 
00625         /* Sanity checks */
00626         if ( ! mac_address ) {
00627                 DBGC ( fcoe, "FCoE %s received VLAN notification missing MAC "
00628                        "address\n", fcoe->netdev->name );
00629                 return -EINVAL;
00630         }
00631         if ( ! vlan ) {
00632                 DBGC ( fcoe, "FCoE %s received VLAN notification missing VLAN "
00633                        "tag\n", fcoe->netdev->name );
00634                 return -EINVAL;
00635         }
00636 
00637         /* Create VLAN */
00638         tag = ntohs ( vlan->vlan );
00639         DBGC ( fcoe, "FCoE %s creating VLAN %d for FCF %s\n",
00640                fcoe->netdev->name, tag, eth_ntoa ( mac_address->mac ) );
00641         if ( ( rc = vlan_create ( fcoe->netdev, tag,
00642                                   FCOE_VLAN_PRIORITY ) ) != 0 ) {
00643                 DBGC ( fcoe, "FCoE %s could not create VLAN %d: %s\n",
00644                        fcoe->netdev->name, tag, strerror ( rc ) );
00645                 return rc;
00646         }
00647 
00648         /* Record that a VLAN was found.  This FCoE port will play no
00649          * further active role; the real FCoE traffic will use the
00650          * port automatically created for the new VLAN device.
00651          */
00652         fcoe->flags |= FCOE_VLAN_FOUND;
00653 
00654         return 0;
00655 }
00656 
00657 /**
00658  * Send FIP discovery solicitation
00659  *
00660  * @v fcoe              FCoE port
00661  * @ret rc              Return status code
00662  */
00663 static int fcoe_fip_tx_solicitation ( struct fcoe_port *fcoe ) {
00664         struct io_buffer *iobuf;
00665         struct {
00666                 struct fip_header hdr;
00667                 struct fip_mac_address mac_address;
00668                 struct fip_name_id name_id;
00669                 struct fip_max_fcoe_size max_fcoe_size;
00670         } __attribute__ (( packed )) *solicitation;
00671         int rc;
00672 
00673         /* Allocate I/O buffer */
00674         iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *solicitation ) );
00675         if ( ! iobuf )
00676                 return -ENOMEM;
00677         iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
00678 
00679         /* Construct discovery solicitation */
00680         solicitation = iob_put ( iobuf, sizeof ( *solicitation ) );
00681         memset ( solicitation, 0, sizeof ( *solicitation ) );
00682         solicitation->hdr.version = FIP_VERSION;
00683         solicitation->hdr.code = htons ( FIP_CODE_DISCOVERY );
00684         solicitation->hdr.subcode = FIP_DISCOVERY_SOLICIT;
00685         solicitation->hdr.len = htons ( ( sizeof ( *solicitation ) -
00686                                           sizeof ( solicitation->hdr ) ) / 4 );
00687         solicitation->hdr.flags = htons ( FIP_FP | FIP_SP );
00688         solicitation->mac_address.type = FIP_MAC_ADDRESS;
00689         solicitation->mac_address.len =
00690                 ( sizeof ( solicitation->mac_address ) / 4 );
00691         memcpy ( solicitation->mac_address.mac, fcoe->netdev->ll_addr,
00692                  sizeof ( solicitation->mac_address.mac ) );
00693         solicitation->name_id.type = FIP_NAME_ID;
00694         solicitation->name_id.len = ( sizeof ( solicitation->name_id ) / 4 );
00695         memcpy ( &solicitation->name_id.name, &fcoe->node_wwn.fc,
00696                  sizeof ( solicitation->name_id.name ) );
00697         solicitation->max_fcoe_size.type = FIP_MAX_FCOE_SIZE;
00698         solicitation->max_fcoe_size.len =
00699                 ( sizeof ( solicitation->max_fcoe_size ) / 4 );
00700         solicitation->max_fcoe_size.mtu =
00701                 htons ( ETH_MAX_MTU - sizeof ( struct fcoe_header ) -
00702                         sizeof ( struct fcoe_footer ) );
00703 
00704         /* Send discovery solicitation */
00705         if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev,
00706                              &fip_protocol, all_fcf_macs,
00707                              fcoe->netdev->ll_addr ) ) != 0 ) {
00708                 DBGC ( fcoe, "FCoE %s could not send discovery solicitation: "
00709                        "%s\n", fcoe->netdev->name, strerror ( rc ) );
00710                 return rc;
00711         }
00712 
00713         return 0;
00714 }
00715 
00716 /**
00717  * Handle received FIP discovery advertisement
00718  *
00719  * @v fcoe              FCoE port
00720  * @v descs             Descriptor list
00721  * @v flags             Flags
00722  * @ret rc              Return status code
00723  */
00724 static int fcoe_fip_rx_advertisement ( struct fcoe_port *fcoe,
00725                                        struct fip_descriptors *descs,
00726                                        unsigned int flags ) {
00727         struct fip_priority *priority = fip_priority ( descs );
00728         struct fip_mac_address *mac_address = fip_mac_address ( descs );
00729         struct fip_fka_adv_p *fka_adv_p = fip_fka_adv_p ( descs );
00730 
00731         /* Sanity checks */
00732         if ( ! priority ) {
00733                 DBGC ( fcoe, "FCoE %s received advertisement missing "
00734                        "priority\n", fcoe->netdev->name );
00735                 return -EINVAL;
00736         }
00737         if ( ! mac_address ) {
00738                 DBGC ( fcoe, "FCoE %s received advertisement missing MAC "
00739                        "address\n", fcoe->netdev->name );
00740                 return -EINVAL;
00741         }
00742         if ( ! fka_adv_p ) {
00743                 DBGC ( fcoe, "FCoE %s received advertisement missing FKA ADV "
00744                        "period\n", fcoe->netdev->name );
00745                 return -EINVAL;
00746         }
00747 
00748         if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) {
00749 
00750                 /* We are soliciting for an FCF.  Store the highest
00751                  * (i.e. lowest-valued) priority solicited
00752                  * advertisement that we receive.
00753                  */
00754                 if ( ( ( flags & ( FIP_A | FIP_S | FIP_F ) ) ==
00755                        ( FIP_A | FIP_S | FIP_F ) ) &&
00756                      ( priority->priority < fcoe->priority ) ) {
00757 
00758                         fcoe->flags |= FCOE_HAVE_FIP_FCF;
00759                         fcoe->priority = priority->priority;
00760                         if ( fka_adv_p->flags & FIP_NO_KEEPALIVE ) {
00761                                 fcoe->keepalive = 0;
00762                         } else {
00763                                 fcoe->keepalive = ntohl ( fka_adv_p->period );
00764                         }
00765                         fcoe->flags &= ~FCOE_FCF_ALLOWS_SPMA;
00766                         if ( flags & FIP_SP )
00767                                 fcoe->flags |= FCOE_FCF_ALLOWS_SPMA;
00768                         memcpy ( fcoe->fcf_mac, mac_address->mac,
00769                                  sizeof ( fcoe->fcf_mac ) );
00770                         DBGC ( fcoe, "FCoE %s selected FCF %s (pri %d",
00771                                fcoe->netdev->name, eth_ntoa ( fcoe->fcf_mac ),
00772                                fcoe->priority );
00773                         if ( fcoe->keepalive ) {
00774                                 DBGC ( fcoe, ", FKA ADV %dms",
00775                                        fcoe->keepalive );
00776                         }
00777                         DBGC ( fcoe, ", %cPMA)\n",
00778                                ( ( fcoe->flags & FCOE_FCF_ALLOWS_SPMA ) ?
00779                                  'S' : 'F' ) );
00780                 }
00781 
00782         } else if ( fcoe->flags & FCOE_HAVE_FIP_FCF ) {
00783 
00784                 /* We are checking that the FCF remains alive.  Reset
00785                  * the timeout counter if this is an advertisement
00786                  * from our forwarder.
00787                  */
00788                 if ( memcmp ( fcoe->fcf_mac, mac_address->mac,
00789                               sizeof ( fcoe->fcf_mac ) ) == 0 ) {
00790                         fcoe->timeouts = 0;
00791                 }
00792 
00793         } else {
00794 
00795                 /* We are operating in non-FIP mode and have received
00796                  * a FIP advertisement.  Reset the link in order to
00797                  * attempt FIP.
00798                  */
00799                 fcoe_reset ( fcoe );
00800 
00801         }
00802 
00803         return 0;
00804 }
00805 
00806 /**
00807  * Handle received FIP ELS response
00808  *
00809  * @v fcoe              FCoE port
00810  * @v descs             Descriptor list
00811  * @v flags             Flags
00812  * @ret rc              Return status code
00813  */
00814 static int fcoe_fip_rx_els_response ( struct fcoe_port *fcoe,
00815                                       struct fip_descriptors *descs,
00816                                       unsigned int flags __unused ) {
00817         struct fip_els *flogi = fip_flogi ( descs );
00818         struct fip_mac_address *mac_address = fip_mac_address ( descs );
00819         void *frame;
00820         size_t frame_len;
00821         int rc;
00822 
00823         /* Sanity checks */
00824         if ( ! flogi ) {
00825                 DBGC ( fcoe, "FCoE %s received ELS response missing FLOGI\n",
00826                        fcoe->netdev->name );
00827                 return -EINVAL;
00828         }
00829         if ( ! mac_address ) {
00830                 DBGC ( fcoe, "FCoE %s received ELS response missing MAC "
00831                        "address\n", fcoe->netdev->name );
00832                 return -EINVAL;
00833         }
00834 
00835         /* Record local MAC address */
00836         memcpy ( fcoe->local_mac, mac_address->mac, sizeof ( fcoe->local_mac ));
00837         DBGC ( fcoe, "FCoE %s using local MAC %s\n",
00838                fcoe->netdev->name, eth_ntoa ( fcoe->local_mac ) );
00839 
00840         /* Hand off via transport interface */
00841         frame = &flogi->fc;
00842         frame_len = ( ( flogi->len * 4 ) - offsetof ( typeof ( *flogi ), fc ) );
00843         if ( ( rc = xfer_deliver_raw ( &fcoe->transport, frame,
00844                                        frame_len ) ) != 0 ) {
00845                 DBGC ( fcoe, "FCoE %s could not deliver FIP FLOGI frame: %s\n",
00846                        fcoe->netdev->name, strerror ( rc ) );
00847                 return rc;
00848         }
00849 
00850         return 0;
00851 }
00852 
00853 /**
00854  * Send FIP keepalive
00855  *
00856  * @v fcoe              FCoE port
00857  * @ret rc              Return status code
00858  */
00859 static int fcoe_fip_tx_keepalive ( struct fcoe_port *fcoe ) {
00860         struct io_buffer *iobuf;
00861         struct {
00862                 struct fip_header hdr;
00863                 struct fip_mac_address mac_address;
00864         } __attribute__ (( packed )) *keepalive;
00865         int rc;
00866 
00867         /* Allocate I/O buffer */
00868         iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *keepalive ) );
00869         if ( ! iobuf )
00870                 return -ENOMEM;
00871         iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
00872 
00873         /* Construct keepalive */
00874         keepalive = iob_put ( iobuf, sizeof ( *keepalive ) );
00875         memset ( keepalive, 0, sizeof ( *keepalive ) );
00876         keepalive->hdr.version = FIP_VERSION;
00877         keepalive->hdr.code = htons ( FIP_CODE_MAINTAIN );
00878         keepalive->hdr.subcode = FIP_MAINTAIN_KEEP_ALIVE;
00879         keepalive->hdr.len =    htons ( ( sizeof ( *keepalive ) -
00880                                           sizeof ( keepalive->hdr ) ) / 4 );
00881         keepalive->mac_address.type = FIP_MAC_ADDRESS;
00882         keepalive->mac_address.len =
00883                 ( sizeof ( keepalive->mac_address ) / 4 );
00884         memcpy ( keepalive->mac_address.mac, fcoe->netdev->ll_addr,
00885                  sizeof ( keepalive->mac_address.mac ) );
00886 
00887         /* Send keepalive */
00888         if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev,
00889                              &fip_protocol, fcoe->fcf_mac,
00890                              fcoe->netdev->ll_addr ) ) != 0 ) {
00891                 DBGC ( fcoe, "FCoE %s could not send keepalive: %s\n",
00892                        fcoe->netdev->name, strerror ( rc ) );
00893                 return rc;
00894         }
00895 
00896         return 0;
00897 }
00898 
00899 /** A FIP handler */
00900 struct fip_handler {
00901         /** Protocol code */
00902         uint16_t code;
00903         /** Protocol subcode */
00904         uint8_t subcode;
00905         /**
00906          * Receive FIP packet
00907          *
00908          * @v fcoe              FCoE port
00909          * @v descs             Descriptor list
00910          * @v flags             Flags
00911          * @ret rc              Return status code
00912          */
00913         int ( * rx ) ( struct fcoe_port *fcoe, struct fip_descriptors *descs,
00914                        unsigned int flags );
00915 };
00916 
00917 /** FIP handlers */
00918 static struct fip_handler fip_handlers[] = {
00919         { FIP_CODE_VLAN, FIP_VLAN_NOTIFY,
00920           fcoe_fip_rx_vlan },
00921         { FIP_CODE_DISCOVERY, FIP_DISCOVERY_ADVERTISE,
00922           fcoe_fip_rx_advertisement },
00923         { FIP_CODE_ELS, FIP_ELS_RESPONSE,
00924           fcoe_fip_rx_els_response },
00925 };
00926 
00927 /**
00928  * Process incoming FIP packets
00929  *
00930  * @v iobuf             I/O buffer
00931  * @v netdev            Network device
00932  * @v ll_dest           Link-layer destination address
00933  * @v ll_source         Link-layer source address
00934  * @v flags             Packet flags
00935  * @ret rc              Return status code
00936  */
00937 static int fcoe_fip_rx ( struct io_buffer *iobuf,
00938                          struct net_device *netdev,
00939                          const void *ll_dest,
00940                          const void *ll_source __unused,
00941                          unsigned int flags __unused ) {
00942         struct fip_header *fiphdr = iobuf->data;
00943         struct fip_descriptors descs;
00944         struct fip_handler *handler;
00945         struct fcoe_port *fcoe;
00946         unsigned int i;
00947         int rc;
00948 
00949         /* Identify FCoE port */
00950         if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) {
00951                 DBG ( "FCoE received FIP frame for net device %s missing FCoE "
00952                       "port\n", netdev->name );
00953                 rc = -ENOTCONN;
00954                 goto done;
00955         }
00956 
00957         /* Discard packets not destined for us */
00958         if ( ( memcmp ( fcoe->netdev->ll_addr, ll_dest, ETH_ALEN ) != 0 ) &&
00959              ( memcmp ( all_fcoe_macs, ll_dest,
00960                         sizeof ( all_fcoe_macs ) ) != 0 ) &&
00961              ( memcmp ( all_enode_macs, ll_dest,
00962                         sizeof ( all_enode_macs ) ) != 0 ) ) {
00963                 DBGC2 ( fcoe, "FCoE %s ignoring FIP packet for %s\n",
00964                         fcoe->netdev->name, eth_ntoa ( ll_dest ) );
00965                 rc = -ENOTCONN;
00966                 goto done;
00967         }
00968 
00969         /* Parse FIP packet */
00970         if ( ( rc = fcoe_fip_parse ( fcoe, fiphdr, iob_len ( iobuf ),
00971                                      &descs ) ) != 0 )
00972                 goto done;
00973 
00974         /* Find a suitable handler */
00975         for ( i = 0 ; i < ( sizeof ( fip_handlers ) /
00976                             sizeof ( fip_handlers[0] ) ) ; i++ ) {
00977                 handler = &fip_handlers[i];
00978                 if ( ( handler->code == ntohs ( fiphdr->code ) ) &&
00979                      ( handler->subcode == fiphdr->subcode ) ) {
00980                         rc = handler->rx ( fcoe, &descs,
00981                                            ntohs ( fiphdr->flags ) );
00982                         goto done;
00983                 }
00984         }
00985         DBGC ( fcoe, "FCoE %s received unsupported FIP code %04x.%02x\n",
00986                fcoe->netdev->name, ntohs ( fiphdr->code ), fiphdr->subcode );
00987         rc = -ENOTSUP;
00988 
00989  done:
00990         free_iob ( iobuf );
00991         return rc;
00992 }
00993 
00994 /******************************************************************************
00995  *
00996  * FCoE ports
00997  *
00998  ******************************************************************************
00999  */
01000 
01001 /**
01002  * Handle FCoE timer expiry
01003  *
01004  * @v timer             FIP timer
01005  * @v over              Timer expired
01006  */
01007 static void fcoe_expired ( struct retry_timer *timer, int over __unused ) {
01008         struct fcoe_port *fcoe =
01009                 container_of ( timer, struct fcoe_port, timer );
01010         int rc;
01011 
01012         /* Sanity check */
01013         assert ( fcoe->flags & FCOE_HAVE_NETWORK );
01014 
01015         /* Increment the timeout counter */
01016         fcoe->timeouts++;
01017 
01018         if ( vlan_can_be_trunk ( fcoe->netdev ) &&
01019              ! ( fcoe->flags & FCOE_VLAN_TIMED_OUT ) ) {
01020 
01021                 /* If we have already found a VLAN, send infrequent
01022                  * VLAN requests, in case VLAN information changes.
01023                  */
01024                 if ( fcoe->flags & FCOE_VLAN_FOUND ) {
01025                         fcoe->flags &= ~FCOE_VLAN_FOUND;
01026                         fcoe->timeouts = 0;
01027                         start_timer_fixed ( &fcoe->timer,
01028                                             FCOE_VLAN_POLL_DELAY );
01029                         fcoe_fip_tx_vlan ( fcoe );
01030                         return;
01031                 }
01032 
01033                 /* If we have not yet found a VLAN, and we have not
01034                  * yet timed out and given up on finding one, then
01035                  * send a VLAN request and wait.
01036                  */
01037                 if ( fcoe->timeouts <= FCOE_MAX_VLAN_REQUESTS ) {
01038                         start_timer_fixed ( &fcoe->timer,
01039                                             FCOE_VLAN_RETRY_DELAY );
01040                         fcoe_fip_tx_vlan ( fcoe );
01041                         return;
01042                 }
01043 
01044                 /* We have timed out waiting for a VLAN; proceed to
01045                  * FIP discovery.
01046                  */
01047                 fcoe->flags |= FCOE_VLAN_TIMED_OUT;
01048                 fcoe->timeouts = 0;
01049                 DBGC ( fcoe, "FCoE %s giving up on VLAN discovery\n",
01050                        fcoe->netdev->name );
01051                 start_timer_nodelay ( &fcoe->timer );
01052 
01053         } else if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) {
01054 
01055                 /* If we have not yet found a FIP-capable forwarder,
01056                  * and we have not yet timed out and given up on
01057                  * finding one, then send a FIP solicitation and wait.
01058                  */
01059                 start_timer_fixed ( &fcoe->timer, FCOE_FIP_RETRY_DELAY );
01060                 if ( ( ! ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ) &&
01061                      ( fcoe->timeouts <= FCOE_MAX_FIP_SOLICITATIONS ) ) {
01062                         fcoe_fip_tx_solicitation ( fcoe );
01063                         return;
01064                 }
01065 
01066                 /* Attach Fibre Channel port */
01067                 if ( ( rc = fc_port_open ( &fcoe->transport, &fcoe->node_wwn.fc,
01068                                            &fcoe->port_wwn.fc,
01069                                            fcoe->netdev->name ) ) != 0 ) {
01070                         DBGC ( fcoe, "FCoE %s could not create FC port: %s\n",
01071                                fcoe->netdev->name, strerror ( rc ) );
01072                         /* We will try again on the next timer expiry */
01073                         return;
01074                 }
01075                 stop_timer ( &fcoe->timer );
01076 
01077                 /* Either we have found a FIP-capable forwarder, or we
01078                  * have timed out and will fall back to pre-FIP mode.
01079                  */
01080                 fcoe->flags |= FCOE_HAVE_FCF;
01081                 fcoe->timeouts = 0;
01082                 DBGC ( fcoe, "FCoE %s using %sFIP FCF %s\n", fcoe->netdev->name,
01083                        ( ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ? "" : "non-" ),
01084                        eth_ntoa ( fcoe->fcf_mac ) );
01085 
01086                 /* Start sending keepalives if applicable */
01087                 if ( fcoe->keepalive )
01088                         start_timer_nodelay ( &fcoe->timer );
01089 
01090                 /* Send notification of window change */
01091                 xfer_window_changed ( &fcoe->transport );
01092 
01093         } else {
01094 
01095                 /* Send keepalive */
01096                 start_timer_fixed ( &fcoe->timer,
01097                                     ( fcoe->keepalive * TICKS_PER_MS ) );
01098                 fcoe_fip_tx_keepalive ( fcoe );
01099 
01100                 /* Abandon FCF if we have not seen its advertisements */
01101                 if ( fcoe->timeouts > FCOE_MAX_FIP_MISSING_KEEPALIVES ) {
01102                         DBGC ( fcoe, "FCoE %s abandoning FCF %s\n",
01103                                fcoe->netdev->name, eth_ntoa ( fcoe->fcf_mac ));
01104                         fcoe_reset ( fcoe );
01105                 }
01106         }
01107 }
01108 
01109 /**
01110  * Create FCoE port
01111  *
01112  * @v netdev            Network device
01113  * @ret rc              Return status code
01114  */
01115 static int fcoe_probe ( struct net_device *netdev ) {
01116         struct ll_protocol *ll_protocol = netdev->ll_protocol;
01117         struct fcoe_port *fcoe;
01118         int rc;
01119 
01120         /* Sanity check */
01121         if ( ll_protocol->ll_proto != htons ( ARPHRD_ETHER ) ) {
01122                 /* Not an error; simply skip this net device */
01123                 DBG ( "FCoE skipping non-Ethernet device %s\n", netdev->name );
01124                 rc = 0;
01125                 goto err_non_ethernet;
01126         }
01127 
01128         /* Allocate and initialise structure */
01129         fcoe = zalloc ( sizeof ( *fcoe ) );
01130         if ( ! fcoe ) {
01131                 rc = -ENOMEM;
01132                 goto err_zalloc;
01133         }
01134         ref_init ( &fcoe->refcnt, NULL );
01135         intf_init ( &fcoe->transport, &fcoe_transport_desc, &fcoe->refcnt );
01136         timer_init ( &fcoe->timer, fcoe_expired, &fcoe->refcnt );
01137         fcoe->netdev = netdev_get ( netdev );
01138 
01139         /* Construct node and port names */
01140         fcoe->node_wwn.fcoe.authority = htons ( FCOE_AUTHORITY_IEEE );
01141         memcpy ( &fcoe->node_wwn.fcoe.mac, netdev->ll_addr,
01142                  sizeof ( fcoe->node_wwn.fcoe.mac ) );
01143         fcoe->port_wwn.fcoe.authority = htons ( FCOE_AUTHORITY_IEEE_EXTENDED );
01144         memcpy ( &fcoe->port_wwn.fcoe.mac, netdev->ll_addr,
01145                  sizeof ( fcoe->port_wwn.fcoe.mac ) );
01146 
01147         DBGC ( fcoe, "FCoE %s is %s", fcoe->netdev->name,
01148                fc_ntoa ( &fcoe->node_wwn.fc ) );
01149         DBGC ( fcoe, " port %s\n", fc_ntoa ( &fcoe->port_wwn.fc ) );
01150 
01151         /* Transfer reference to port list */
01152         list_add ( &fcoe->list, &fcoe_ports );
01153         return 0;
01154 
01155         netdev_put ( fcoe->netdev );
01156  err_zalloc:
01157  err_non_ethernet:
01158         return rc;
01159 }
01160 
01161 /**
01162  * Handle FCoE port device or link state change
01163  *
01164  * @v netdev            Network device
01165  */
01166 static void fcoe_notify ( struct net_device *netdev ) {
01167         struct fcoe_port *fcoe;
01168 
01169         /* Sanity check */
01170         if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) {
01171                 DBG ( "FCoE notification for net device %s missing FCoE "
01172                       "port\n", netdev->name );
01173                 return;
01174         }
01175 
01176         /* Reset the FCoE link if necessary */
01177         if ( ! ( netdev_is_open ( netdev ) &&
01178                  netdev_link_ok ( netdev ) &&
01179                  ( fcoe->flags & FCOE_HAVE_NETWORK ) ) ) {
01180                 fcoe_reset ( fcoe );
01181         }
01182 }
01183 
01184 /**
01185  * Destroy FCoE port
01186  *
01187  * @v netdev            Network device
01188  */
01189 static void fcoe_remove ( struct net_device *netdev ) {
01190         struct fcoe_port *fcoe;
01191 
01192         /* Sanity check */
01193         if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) {
01194                 DBG ( "FCoE removal of net device %s missing FCoE port\n",
01195                       netdev->name );
01196                 return;
01197         }
01198 
01199         /* Close FCoE device */
01200         fcoe_close ( fcoe, 0 );
01201 }
01202 
01203 /** FCoE driver */
01204 struct net_driver fcoe_driver __net_driver = {
01205         .name = "FCoE",
01206         .probe = fcoe_probe,
01207         .notify = fcoe_notify,
01208         .remove = fcoe_remove,
01209 };
01210 
01211 /** FCoE protocol */
01212 struct net_protocol fcoe_protocol __net_protocol = {
01213         .name = "FCoE",
01214         .net_proto = htons ( ETH_P_FCOE ),
01215         .rx = fcoe_rx,
01216 };
01217 
01218 /** FIP protocol */
01219 struct net_protocol fip_protocol __net_protocol = {
01220         .name = "FIP",
01221         .net_proto = htons ( ETH_P_FIP ),
01222         .rx = fcoe_fip_rx,
01223 };
01224 
01225 /** Human-readable message for CRC errors
01226  *
01227  * It seems as though several drivers neglect to strip the Ethernet
01228  * CRC, which will cause the FCoE footer to be misplaced and result
01229  * (coincidentally) in an "invalid CRC" error from FCoE.
01230  */
01231 struct errortab fcoe_errors[] __errortab = {
01232         __einfo_errortab ( EINFO_EINVAL_CRC ),
01233 };