Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / net / fcoe.c
1 /*
2  * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  */
19
20 FILE_LICENCE ( GPL2_OR_LATER );
21
22 #include <stddef.h>
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <byteswap.h>
26 #include <ipxe/if_ether.h>
27 #include <ipxe/if_arp.h>
28 #include <ipxe/iobuf.h>
29 #include <ipxe/interface.h>
30 #include <ipxe/xfer.h>
31 #include <ipxe/netdevice.h>
32 #include <ipxe/ethernet.h>
33 #include <ipxe/vlan.h>
34 #include <ipxe/features.h>
35 #include <ipxe/errortab.h>
36 #include <ipxe/device.h>
37 #include <ipxe/crc32.h>
38 #include <ipxe/retry.h>
39 #include <ipxe/timer.h>
40 #include <ipxe/fc.h>
41 #include <ipxe/fip.h>
42 #include <ipxe/fcoe.h>
43
44 /** @file
45  *
46  * FCoE protocol
47  *
48  */
49
50 FEATURE ( FEATURE_PROTOCOL, "FCoE", DHCP_EB_FEATURE_FCOE, 1 );
51
52 /* Disambiguate the various error causes */
53 #define EINVAL_UNDERLENGTH __einfo_error ( EINFO_EINVAL_UNDERLENGTH )
54 #define EINFO_EINVAL_UNDERLENGTH \
55         __einfo_uniqify ( EINFO_EINVAL, 0x01, "Underlength packet" )
56 #define EINVAL_SOF __einfo_error ( EINFO_EINVAL_SOF )
57 #define EINFO_EINVAL_SOF \
58         __einfo_uniqify ( EINFO_EINVAL, 0x02, "Invalid SoF delimiter" )
59 #define EINVAL_CRC __einfo_error ( EINFO_EINVAL_CRC )
60 #define EINFO_EINVAL_CRC \
61         __einfo_uniqify ( EINFO_EINVAL, 0x03, "Invalid CRC (not stripped?)" )
62 #define EINVAL_EOF __einfo_error ( EINFO_EINVAL_EOF )
63 #define EINFO_EINVAL_EOF \
64         __einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid EoF delimiter" )
65
66 /** An FCoE port */
67 struct fcoe_port {
68         /** Reference count */
69         struct refcnt refcnt;
70         /** List of FCoE ports */
71         struct list_head list;
72         /** Transport interface */
73         struct interface transport;
74         /** Network device */
75         struct net_device *netdev;
76
77         /** Node WWN */
78         union fcoe_name node_wwn;
79         /** Port WWN */
80         union fcoe_name port_wwn;
81
82         /** FIP retransmission timer */
83         struct retry_timer timer;
84         /** FIP timeout counter */
85         unsigned int timeouts;
86         /** Flags */
87         unsigned int flags;
88         /** FCoE forwarder priority */
89         unsigned int priority;
90         /** Keepalive delay (in ms) */
91         unsigned int keepalive;
92         /** FCoE forwarder MAC address */
93         uint8_t fcf_mac[ETH_ALEN];
94         /** Local MAC address */
95         uint8_t local_mac[ETH_ALEN];
96 };
97
98 /** FCoE flags */
99 enum fcoe_flags {
100         /** Underlying network device is available */
101         FCOE_HAVE_NETWORK = 0x0001,
102         /** We have selected an FCoE forwarder to use */
103         FCOE_HAVE_FCF = 0x0002,
104         /** We have a FIP-capable FCoE forwarder available to be used */
105         FCOE_HAVE_FIP_FCF = 0x0004,
106         /** FCoE forwarder supports server-provided MAC addresses */
107         FCOE_FCF_ALLOWS_SPMA = 0x0008,
108         /** An alternative VLAN has been found */
109         FCOE_VLAN_FOUND = 0x0010,
110         /** VLAN discovery has timed out */
111         FCOE_VLAN_TIMED_OUT = 0x0020,
112 };
113
114 struct net_protocol fcoe_protocol __net_protocol;
115 struct net_protocol fip_protocol __net_protocol;
116
117 /** FCoE All-FCoE-MACs address */
118 static uint8_t all_fcoe_macs[ETH_ALEN] =
119         { 0x01, 0x10, 0x18, 0x01, 0x00, 0x00 };
120
121 /** FCoE All-ENode-MACs address */
122 static uint8_t all_enode_macs[ETH_ALEN] =
123         { 0x01, 0x10, 0x18, 0x01, 0x00, 0x01 };
124
125 /** FCoE All-FCF-MACs address */
126 static uint8_t all_fcf_macs[ETH_ALEN] =
127         { 0x01, 0x10, 0x18, 0x01, 0x00, 0x02 };
128
129 /** Default FCoE forwarded MAC address */
130 static uint8_t default_fcf_mac[ETH_ALEN] =
131         { 0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe };
132
133 /** Maximum number of VLAN requests before giving up on VLAN discovery */
134 #define FCOE_MAX_VLAN_REQUESTS 2
135
136 /** Delay between retrying VLAN requests */
137 #define FCOE_VLAN_RETRY_DELAY ( TICKS_PER_SEC )
138
139 /** Delay between retrying polling VLAN requests */
140 #define FCOE_VLAN_POLL_DELAY ( 30 * TICKS_PER_SEC )
141
142 /** Maximum number of FIP solicitations before giving up on FIP */
143 #define FCOE_MAX_FIP_SOLICITATIONS 2
144
145 /** Delay between retrying FIP solicitations */
146 #define FCOE_FIP_RETRY_DELAY ( TICKS_PER_SEC )
147
148 /** Maximum number of missing discovery advertisements */
149 #define FCOE_MAX_FIP_MISSING_KEEPALIVES 4
150
151 /** List of FCoE ports */
152 static LIST_HEAD ( fcoe_ports );
153
154 /******************************************************************************
155  *
156  * FCoE protocol
157  *
158  ******************************************************************************
159  */
160
161 /**
162  * Identify FCoE port by network device
163  *
164  * @v netdev            Network device
165  * @ret fcoe            FCoE port, or NULL
166  */
167 static struct fcoe_port * fcoe_demux ( struct net_device *netdev ) {
168         struct fcoe_port *fcoe;
169
170         list_for_each_entry ( fcoe, &fcoe_ports, list ) {
171                 if ( fcoe->netdev == netdev )
172                         return fcoe;
173         }
174         return NULL;
175 }
176
177 /**
178  * Reset FCoE port
179  *
180  * @v fcoe              FCoE port
181  */
182 static void fcoe_reset ( struct fcoe_port *fcoe ) {
183
184         /* Detach FC port, if any */
185         intf_restart ( &fcoe->transport, -ECANCELED );
186
187         /* Reset any FIP state */
188         stop_timer ( &fcoe->timer );
189         fcoe->timeouts = 0;
190         fcoe->flags = 0;
191         fcoe->priority = ( FIP_LOWEST_PRIORITY + 1 );
192         fcoe->keepalive = 0;
193         memcpy ( fcoe->fcf_mac, default_fcf_mac,
194                  sizeof ( fcoe->fcf_mac ) );
195         memcpy ( fcoe->local_mac, fcoe->netdev->ll_addr,
196                  sizeof ( fcoe->local_mac ) );
197
198         /* Start FIP solicitation if network is available */
199         if ( netdev_is_open ( fcoe->netdev ) &&
200              netdev_link_ok ( fcoe->netdev ) ) {
201                 fcoe->flags |= FCOE_HAVE_NETWORK;
202                 start_timer_nodelay ( &fcoe->timer );
203                 DBGC ( fcoe, "FCoE %s starting %s\n", fcoe->netdev->name,
204                        ( vlan_can_be_trunk ( fcoe->netdev ) ?
205                          "VLAN discovery" : "FIP solicitation" ) );
206         }
207
208         /* Send notification of window change */
209         xfer_window_changed ( &fcoe->transport );
210 }
211
212 /**
213  * Transmit FCoE packet
214  *
215  * @v fcoe              FCoE port
216  * @v iobuf             I/O buffer
217  * @v meta              Data transfer metadata
218  * @ret rc              Return status code
219  */
220 static int fcoe_deliver ( struct fcoe_port *fcoe,
221                           struct io_buffer *iobuf,
222                           struct xfer_metadata *meta __unused ) {
223         struct fc_frame_header *fchdr = iobuf->data;
224         struct fc_els_frame_common *els = ( iobuf->data + sizeof ( *fchdr ) );
225         struct fcoe_header *fcoehdr;
226         struct fcoe_footer *fcoeftr;
227         struct fip_header *fiphdr;
228         struct fip_login *fipflogi;
229         struct fip_mac_address *fipmac;
230         uint32_t crc;
231         struct net_protocol *net_protocol;
232         void *ll_source;
233         int rc;
234
235         /* Send as FIP or FCoE as appropriate */
236         if ( ( fchdr->r_ctl == ( FC_R_CTL_ELS | FC_R_CTL_UNSOL_CTRL ) ) &&
237              ( els->command == FC_ELS_FLOGI ) &&
238              ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ) {
239
240                 /* Create FIP FLOGI descriptor */
241                 fipflogi = iob_push ( iobuf,
242                                       offsetof ( typeof ( *fipflogi ), fc ) );
243                 memset ( fipflogi, 0, offsetof ( typeof ( *fipflogi ), fc ) );
244                 fipflogi->type = FIP_FLOGI;
245                 fipflogi->len = ( iob_len ( iobuf ) / 4 );
246
247                 /* Create FIP MAC address descriptor */
248                 fipmac = iob_put ( iobuf, sizeof ( *fipmac ) );
249                 memset ( fipmac, 0, sizeof ( *fipmac ) );
250                 fipmac->type = FIP_MAC_ADDRESS;
251                 fipmac->len = ( sizeof ( *fipmac ) / 4 );
252                 if ( fcoe->flags & FCOE_FCF_ALLOWS_SPMA ) {
253                         memcpy ( fipmac->mac, fcoe->netdev->ll_addr,
254                                  sizeof ( fipmac->mac ) );
255                 }
256
257                 /* Create FIP header */
258                 fiphdr = iob_push ( iobuf, sizeof ( *fiphdr ) );
259                 memset ( fiphdr, 0, sizeof ( *fiphdr ) );
260                 fiphdr->version = FIP_VERSION;
261                 fiphdr->code = htons ( FIP_CODE_ELS );
262                 fiphdr->subcode = FIP_ELS_REQUEST;
263                 fiphdr->len =
264                         htons ( ( iob_len ( iobuf ) - sizeof ( *fiphdr ) ) / 4);
265                 fiphdr->flags = ( ( fcoe->flags & FCOE_FCF_ALLOWS_SPMA ) ?
266                                   htons ( FIP_SP ) : htons ( FIP_FP ) );
267
268                 /* Send as FIP packet from netdev's own MAC address */
269                 net_protocol = &fip_protocol;
270                 ll_source = fcoe->netdev->ll_addr;
271
272         } else {
273
274                 /* Calculate CRC */
275                 crc = crc32_le ( ~((uint32_t)0), iobuf->data,
276                                  iob_len ( iobuf ) );
277
278                 /* Create FCoE header */
279                 fcoehdr = iob_push ( iobuf, sizeof ( *fcoehdr ) );
280                 memset ( fcoehdr, 0, sizeof ( *fcoehdr ) );
281                 fcoehdr->sof = ( ( fchdr->seq_cnt == ntohs ( 0 ) ) ?
282                                  FCOE_SOF_I3 : FCOE_SOF_N3 );
283
284                 /* Create FCoE footer */
285                 fcoeftr = iob_put ( iobuf, sizeof ( *fcoeftr ) );
286                 memset ( fcoeftr, 0, sizeof ( *fcoeftr ) );
287                 fcoeftr->crc = cpu_to_le32 ( crc ^ ~((uint32_t)0) );
288                 fcoeftr->eof = ( ( fchdr->f_ctl_es & FC_F_CTL_ES_END ) ?
289                                  FCOE_EOF_T : FCOE_EOF_N );
290
291                 /* Send as FCoE packet from FCoE MAC address */
292                 net_protocol = &fcoe_protocol;
293                 ll_source = fcoe->local_mac;
294         }
295
296         /* Transmit packet */
297         if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev, net_protocol,
298                              fcoe->fcf_mac, ll_source ) ) != 0 ) {
299                 DBGC ( fcoe, "FCoE %s could not transmit: %s\n",
300                        fcoe->netdev->name, strerror ( rc ) );
301                 goto done;
302         }
303
304  done:
305         free_iob ( iobuf );
306         return rc;
307 }
308
309 /**
310  * Allocate FCoE I/O buffer
311  *
312  * @v len               Payload length
313  * @ret iobuf           I/O buffer, or NULL
314  */
315 static struct io_buffer * fcoe_alloc_iob ( struct fcoe_port *fcoe __unused,
316                                            size_t len ) {
317         struct io_buffer *iobuf;
318
319         iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( struct fcoe_header ) +
320                             len + sizeof ( struct fcoe_footer ) );
321         if ( iobuf ) {
322                 iob_reserve ( iobuf, ( MAX_LL_HEADER_LEN +
323                                        sizeof ( struct fcoe_header ) ) );
324         }
325         return iobuf;
326 }
327
328 /**
329  * Process incoming FCoE packets
330  *
331  * @v iobuf             I/O buffer
332  * @v netdev            Network device
333  * @v ll_dest           Link-layer destination address
334  * @v ll_source         Link-layer source address
335  * @v flags             Packet flags
336  * @ret rc              Return status code
337  */
338 static int fcoe_rx ( struct io_buffer *iobuf, struct net_device *netdev,
339                      const void *ll_dest, const void *ll_source,
340                      unsigned int flags __unused ) {
341         struct fcoe_header *fcoehdr;
342         struct fcoe_footer *fcoeftr;
343         struct fcoe_port *fcoe;
344         int rc;
345
346         /* Identify FCoE port */
347         if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) {
348                 DBG ( "FCoE received frame for net device %s missing FCoE "
349                       "port\n", netdev->name );
350                 rc = -ENOTCONN;
351                 goto done;
352         }
353
354         /* Discard packets not destined for us */
355         if ( ( memcmp ( fcoe->local_mac, ll_dest,
356                         sizeof ( fcoe->local_mac ) ) != 0 ) &&
357              ( memcmp ( default_fcf_mac, ll_dest,
358                         sizeof ( default_fcf_mac ) ) != 0 ) ) {
359                 DBGC2 ( fcoe, "FCoE %s ignoring packet for %s\n",
360                         fcoe->netdev->name, eth_ntoa ( ll_dest ) );
361                 rc = -ENOTCONN;
362                 goto done;
363         }
364
365         /* Sanity check */
366         if ( iob_len ( iobuf ) < ( sizeof ( *fcoehdr ) + sizeof ( *fcoeftr ) )){
367                 DBGC ( fcoe, "FCoE %s received under-length frame (%zd "
368                        "bytes)\n", fcoe->netdev->name, iob_len ( iobuf ) );
369                 rc = -EINVAL_UNDERLENGTH;
370                 goto done;
371         }
372
373         /* Strip header and footer */
374         fcoehdr = iobuf->data;
375         iob_pull ( iobuf, sizeof ( *fcoehdr ) );
376         fcoeftr = ( iobuf->data + iob_len ( iobuf ) - sizeof ( *fcoeftr ) );
377         iob_unput ( iobuf, sizeof ( *fcoeftr ) );
378
379         /* Validity checks */
380         if ( fcoehdr->version != FCOE_FRAME_VER ) {
381                 DBGC ( fcoe, "FCoE %s received unsupported frame version "
382                        "%02x\n", fcoe->netdev->name, fcoehdr->version );
383                 rc = -EPROTONOSUPPORT;
384                 goto done;
385         }
386         if ( ! ( ( fcoehdr->sof == FCOE_SOF_I3 ) ||
387                  ( fcoehdr->sof == FCOE_SOF_N3 ) ) ) {
388                 DBGC ( fcoe, "FCoE %s received unsupported start-of-frame "
389                        "delimiter %02x\n", fcoe->netdev->name, fcoehdr->sof );
390                 rc = -EINVAL_SOF;
391                 goto done;
392         }
393         if ( ( le32_to_cpu ( fcoeftr->crc ) ^ ~((uint32_t)0) ) !=
394              crc32_le ( ~((uint32_t)0), iobuf->data, iob_len ( iobuf ) ) ) {
395                 DBGC ( fcoe, "FCoE %s received invalid CRC\n",
396                        fcoe->netdev->name );
397                 rc = -EINVAL_CRC;
398                 goto done;
399         }
400         if ( ! ( ( fcoeftr->eof == FCOE_EOF_N ) ||
401                  ( fcoeftr->eof == FCOE_EOF_T ) ) ) {
402                 DBGC ( fcoe, "FCoE %s received unsupported end-of-frame "
403                        "delimiter %02x\n", fcoe->netdev->name, fcoeftr->eof );
404                 rc = -EINVAL_EOF;
405                 goto done;
406         }
407
408         /* Record FCF address if applicable */
409         if ( ( fcoe->flags & FCOE_HAVE_FCF ) &&
410              ( ! ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ) ) {
411                 memcpy ( &fcoe->fcf_mac, ll_source, sizeof ( fcoe->fcf_mac ) );
412         }
413
414         /* Hand off via transport interface */
415         if ( ( rc = xfer_deliver_iob ( &fcoe->transport,
416                                        iob_disown ( iobuf ) ) ) != 0 ) {
417                 DBGC ( fcoe, "FCoE %s could not deliver frame: %s\n",
418                        fcoe->netdev->name, strerror ( rc ) );
419                 goto done;
420         }
421
422  done:
423         free_iob ( iobuf );
424         return rc;
425 }
426
427 /**
428  * Check FCoE flow control window
429  *
430  * @v fcoe              FCoE port
431  * @ret len             Length of window
432  */
433 static size_t fcoe_window ( struct fcoe_port *fcoe ) {
434         return ( ( fcoe->flags & FCOE_HAVE_FCF ) ? ~( ( size_t ) 0 ) : 0 );
435 }
436
437 /**
438  * Close FCoE port
439  *
440  * @v fcoe              FCoE port
441  * @v rc                Reason for close
442  */
443 static void fcoe_close ( struct fcoe_port *fcoe, int rc ) {
444
445         stop_timer ( &fcoe->timer );
446         intf_shutdown ( &fcoe->transport, rc );
447         netdev_put ( fcoe->netdev );
448         list_del ( &fcoe->list );
449         ref_put ( &fcoe->refcnt );
450 }
451
452 /**
453  * Identify device underlying FCoE port
454  *
455  * @v fcoe              FCoE port
456  * @ret device          Underlying device
457  */
458 static struct device * fcoe_identify_device ( struct fcoe_port *fcoe ) {
459         return fcoe->netdev->dev;
460 }
461
462 /** FCoE transport interface operations */
463 static struct interface_operation fcoe_transport_op[] = {
464         INTF_OP ( xfer_deliver, struct fcoe_port *, fcoe_deliver ),
465         INTF_OP ( xfer_alloc_iob, struct fcoe_port *, fcoe_alloc_iob ),
466         INTF_OP ( xfer_window, struct fcoe_port *, fcoe_window ),
467         INTF_OP ( intf_close, struct fcoe_port *, fcoe_close ),
468         INTF_OP ( identify_device, struct fcoe_port *,
469                   fcoe_identify_device ),
470 };
471
472 /** FCoE transport interface descriptor */
473 static struct interface_descriptor fcoe_transport_desc =
474         INTF_DESC ( struct fcoe_port, transport, fcoe_transport_op );
475
476 /******************************************************************************
477  *
478  * FIP protocol
479  *
480  ******************************************************************************
481  */
482
483 /**
484  * Parse FIP packet into descriptor set
485  *
486  * @v fcoe              FCoE port
487  * @v fiphdr            FIP header
488  * @v len               Length of FIP packet
489  * @v descs             Descriptor set to fill in
490  * @ret rc              Return status code
491  */
492 static int fcoe_fip_parse ( struct fcoe_port *fcoe, struct fip_header *fiphdr,
493                             size_t len, struct fip_descriptors *descs ) {
494         union fip_descriptor *desc;
495         size_t descs_len;
496         size_t desc_len;
497         size_t desc_offset;
498         unsigned int desc_type;
499
500         /* Check FIP version */
501         if ( fiphdr->version != FIP_VERSION ) {
502                 DBGC ( fcoe, "FCoE %s received unsupported FIP version %02x\n",
503                        fcoe->netdev->name, fiphdr->version );
504                 return -EINVAL;
505         }
506
507         /* Check length */
508         descs_len = ( ntohs ( fiphdr->len ) * 4 );
509         if ( ( sizeof ( *fiphdr ) + descs_len ) > len ) {
510                 DBGC ( fcoe, "FCoE %s received bad descriptor list length\n",
511                        fcoe->netdev->name );
512                 return -EINVAL;
513         }
514
515         /* Parse descriptor list */
516         memset ( descs, 0, sizeof ( *descs ) );
517         for ( desc_offset = 0 ;
518               desc_offset <= ( descs_len - sizeof ( desc->common ) ) ;
519               desc_offset += desc_len ) {
520
521                 /* Find descriptor and validate length */
522                 desc = ( ( ( void * ) ( fiphdr + 1 ) ) + desc_offset );
523                 desc_type = desc->common.type;
524                 desc_len = ( desc->common.len * 4 );
525                 if ( desc_len == 0 ) {
526                         DBGC ( fcoe, "FCoE %s received zero-length "
527                                "descriptor\n", fcoe->netdev->name );
528                         return -EINVAL;
529                 }
530                 if ( ( desc_offset + desc_len ) > descs_len ) {
531                         DBGC ( fcoe, "FCoE %s descriptor overrun\n",
532                                fcoe->netdev->name );
533                         return -EINVAL;
534                 }
535
536                 /* Handle descriptors that we understand */
537                 if ( ( desc_type > FIP_RESERVED ) &&
538                      ( desc_type < FIP_NUM_DESCRIPTOR_TYPES ) ) {
539                         /* Use only the first instance of a descriptor */
540                         if ( descs->desc[desc_type] == NULL )
541                                 descs->desc[desc_type] = desc;
542                         continue;
543                 }
544
545                 /* Abort if we cannot understand a critical descriptor */
546                 if ( FIP_IS_CRITICAL ( desc_type ) ) {
547                         DBGC ( fcoe, "FCoE %s cannot understand critical "
548                                "descriptor type %02x\n",
549                                fcoe->netdev->name, desc_type );
550                         return -ENOTSUP;
551                 }
552
553                 /* Ignore non-critical descriptors that we cannot understand */
554         }
555
556         return 0;
557 }
558
559 /**
560  * Send FIP VLAN request
561  *
562  * @v fcoe              FCoE port
563  * @ret rc              Return status code
564  */
565 static int fcoe_fip_tx_vlan ( struct fcoe_port *fcoe ) {
566         struct io_buffer *iobuf;
567         struct {
568                 struct fip_header hdr;
569                 struct fip_mac_address mac_address;
570         } __attribute__ (( packed )) *request;
571         int rc;
572
573         /* Allocate I/O buffer */
574         iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *request ) );
575         if ( ! iobuf )
576                 return -ENOMEM;
577         iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
578
579         /* Construct VLAN request */
580         request = iob_put ( iobuf, sizeof ( *request ) );
581         memset ( request, 0, sizeof ( *request ) );
582         request->hdr.version = FIP_VERSION;
583         request->hdr.code = htons ( FIP_CODE_VLAN );
584         request->hdr.subcode = FIP_VLAN_REQUEST;
585         request->hdr.len = htons ( ( sizeof ( *request ) -
586                                      sizeof ( request->hdr ) ) / 4 );
587         request->mac_address.type = FIP_MAC_ADDRESS;
588         request->mac_address.len =
589                 ( sizeof ( request->mac_address ) / 4 );
590         memcpy ( request->mac_address.mac, fcoe->netdev->ll_addr,
591                  sizeof ( request->mac_address.mac ) );
592
593         /* Send VLAN request */
594         if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev,
595                              &fip_protocol, all_fcf_macs,
596                              fcoe->netdev->ll_addr ) ) != 0 ) {
597                 DBGC ( fcoe, "FCoE %s could not send VLAN request: "
598                        "%s\n", fcoe->netdev->name, strerror ( rc ) );
599                 return rc;
600         }
601
602         return 0;
603 }
604
605 /**
606  * Handle received FIP VLAN notification
607  *
608  * @v fcoe              FCoE port
609  * @v descs             Descriptor list
610  * @v flags             Flags
611  * @ret rc              Return status code
612  */
613 static int fcoe_fip_rx_vlan ( struct fcoe_port *fcoe,
614                               struct fip_descriptors *descs,
615                               unsigned int flags __unused ) {
616         struct fip_mac_address *mac_address = fip_mac_address ( descs );
617         struct fip_vlan *vlan = fip_vlan ( descs );
618         unsigned int tag;
619         int rc;
620
621         /* Sanity checks */
622         if ( ! mac_address ) {
623                 DBGC ( fcoe, "FCoE %s received VLAN notification missing MAC "
624                        "address\n", fcoe->netdev->name );
625                 return -EINVAL;
626         }
627         if ( ! vlan ) {
628                 DBGC ( fcoe, "FCoE %s received VLAN notification missing VLAN "
629                        "tag\n", fcoe->netdev->name );
630                 return -EINVAL;
631         }
632
633         /* Create VLAN */
634         tag = ntohs ( vlan->vlan );
635         DBGC ( fcoe, "FCoE %s creating VLAN %d for FCF %s\n",
636                fcoe->netdev->name, tag, eth_ntoa ( mac_address->mac ) );
637         if ( ( rc = vlan_create ( fcoe->netdev, tag,
638                                   FCOE_VLAN_PRIORITY ) ) != 0 ) {
639                 DBGC ( fcoe, "FCoE %s could not create VLAN %d: %s\n",
640                        fcoe->netdev->name, tag, strerror ( rc ) );
641                 return rc;
642         }
643
644         /* Record that a VLAN was found.  This FCoE port will play no
645          * further active role; the real FCoE traffic will use the
646          * port automatically created for the new VLAN device.
647          */
648         fcoe->flags |= FCOE_VLAN_FOUND;
649
650         return 0;
651 }
652
653 /**
654  * Send FIP discovery solicitation
655  *
656  * @v fcoe              FCoE port
657  * @ret rc              Return status code
658  */
659 static int fcoe_fip_tx_solicitation ( struct fcoe_port *fcoe ) {
660         struct io_buffer *iobuf;
661         struct {
662                 struct fip_header hdr;
663                 struct fip_mac_address mac_address;
664                 struct fip_name_id name_id;
665                 struct fip_max_fcoe_size max_fcoe_size;
666         } __attribute__ (( packed )) *solicitation;
667         int rc;
668
669         /* Allocate I/O buffer */
670         iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *solicitation ) );
671         if ( ! iobuf )
672                 return -ENOMEM;
673         iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
674
675         /* Construct discovery solicitation */
676         solicitation = iob_put ( iobuf, sizeof ( *solicitation ) );
677         memset ( solicitation, 0, sizeof ( *solicitation ) );
678         solicitation->hdr.version = FIP_VERSION;
679         solicitation->hdr.code = htons ( FIP_CODE_DISCOVERY );
680         solicitation->hdr.subcode = FIP_DISCOVERY_SOLICIT;
681         solicitation->hdr.len = htons ( ( sizeof ( *solicitation ) -
682                                           sizeof ( solicitation->hdr ) ) / 4 );
683         solicitation->hdr.flags = htons ( FIP_FP | FIP_SP );
684         solicitation->mac_address.type = FIP_MAC_ADDRESS;
685         solicitation->mac_address.len =
686                 ( sizeof ( solicitation->mac_address ) / 4 );
687         memcpy ( solicitation->mac_address.mac, fcoe->netdev->ll_addr,
688                  sizeof ( solicitation->mac_address.mac ) );
689         solicitation->name_id.type = FIP_NAME_ID;
690         solicitation->name_id.len = ( sizeof ( solicitation->name_id ) / 4 );
691         memcpy ( &solicitation->name_id.name, &fcoe->node_wwn.fc,
692                  sizeof ( solicitation->name_id.name ) );
693         solicitation->max_fcoe_size.type = FIP_MAX_FCOE_SIZE;
694         solicitation->max_fcoe_size.len =
695                 ( sizeof ( solicitation->max_fcoe_size ) / 4 );
696         solicitation->max_fcoe_size.mtu =
697                 htons ( ETH_MAX_MTU - sizeof ( struct fcoe_header ) -
698                         sizeof ( struct fcoe_footer ) );
699
700         /* Send discovery solicitation */
701         if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev,
702                              &fip_protocol, all_fcf_macs,
703                              fcoe->netdev->ll_addr ) ) != 0 ) {
704                 DBGC ( fcoe, "FCoE %s could not send discovery solicitation: "
705                        "%s\n", fcoe->netdev->name, strerror ( rc ) );
706                 return rc;
707         }
708
709         return 0;
710 }
711
712 /**
713  * Handle received FIP discovery advertisement
714  *
715  * @v fcoe              FCoE port
716  * @v descs             Descriptor list
717  * @v flags             Flags
718  * @ret rc              Return status code
719  */
720 static int fcoe_fip_rx_advertisement ( struct fcoe_port *fcoe,
721                                        struct fip_descriptors *descs,
722                                        unsigned int flags ) {
723         struct fip_priority *priority = fip_priority ( descs );
724         struct fip_mac_address *mac_address = fip_mac_address ( descs );
725         struct fip_fka_adv_p *fka_adv_p = fip_fka_adv_p ( descs );
726
727         /* Sanity checks */
728         if ( ! priority ) {
729                 DBGC ( fcoe, "FCoE %s received advertisement missing "
730                        "priority\n", fcoe->netdev->name );
731                 return -EINVAL;
732         }
733         if ( ! mac_address ) {
734                 DBGC ( fcoe, "FCoE %s received advertisement missing MAC "
735                        "address\n", fcoe->netdev->name );
736                 return -EINVAL;
737         }
738         if ( ! fka_adv_p ) {
739                 DBGC ( fcoe, "FCoE %s received advertisement missing FKA ADV "
740                        "period\n", fcoe->netdev->name );
741                 return -EINVAL;
742         }
743
744         if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) {
745
746                 /* We are soliciting for an FCF.  Store the highest
747                  * (i.e. lowest-valued) priority solicited
748                  * advertisement that we receive.
749                  */
750                 if ( ( ( flags & ( FIP_A | FIP_S | FIP_F ) ) ==
751                        ( FIP_A | FIP_S | FIP_F ) ) &&
752                      ( priority->priority < fcoe->priority ) ) {
753
754                         fcoe->flags |= FCOE_HAVE_FIP_FCF;
755                         fcoe->priority = priority->priority;
756                         if ( fka_adv_p->flags & FIP_NO_KEEPALIVE ) {
757                                 fcoe->keepalive = 0;
758                         } else {
759                                 fcoe->keepalive = ntohl ( fka_adv_p->period );
760                         }
761                         fcoe->flags &= ~FCOE_FCF_ALLOWS_SPMA;
762                         if ( flags & FIP_SP )
763                                 fcoe->flags |= FCOE_FCF_ALLOWS_SPMA;
764                         memcpy ( fcoe->fcf_mac, mac_address->mac,
765                                  sizeof ( fcoe->fcf_mac ) );
766                         DBGC ( fcoe, "FCoE %s selected FCF %s (pri %d",
767                                fcoe->netdev->name, eth_ntoa ( fcoe->fcf_mac ),
768                                fcoe->priority );
769                         if ( fcoe->keepalive ) {
770                                 DBGC ( fcoe, ", FKA ADV %dms",
771                                        fcoe->keepalive );
772                         }
773                         DBGC ( fcoe, ", %cPMA)\n",
774                                ( ( fcoe->flags & FCOE_FCF_ALLOWS_SPMA ) ?
775                                  'S' : 'F' ) );
776                 }
777
778         } else if ( fcoe->flags & FCOE_HAVE_FIP_FCF ) {
779
780                 /* We are checking that the FCF remains alive.  Reset
781                  * the timeout counter if this is an advertisement
782                  * from our forwarder.
783                  */
784                 if ( memcmp ( fcoe->fcf_mac, mac_address->mac,
785                               sizeof ( fcoe->fcf_mac ) ) == 0 ) {
786                         fcoe->timeouts = 0;
787                 }
788
789         } else {
790
791                 /* We are operating in non-FIP mode and have received
792                  * a FIP advertisement.  Reset the link in order to
793                  * attempt FIP.
794                  */
795                 fcoe_reset ( fcoe );
796
797         }
798
799         return 0;
800 }
801
802 /**
803  * Handle received FIP ELS response
804  *
805  * @v fcoe              FCoE port
806  * @v descs             Descriptor list
807  * @v flags             Flags
808  * @ret rc              Return status code
809  */
810 static int fcoe_fip_rx_els_response ( struct fcoe_port *fcoe,
811                                       struct fip_descriptors *descs,
812                                       unsigned int flags __unused ) {
813         struct fip_els *flogi = fip_flogi ( descs );
814         struct fip_mac_address *mac_address = fip_mac_address ( descs );
815         void *frame;
816         size_t frame_len;
817         int rc;
818
819         /* Sanity checks */
820         if ( ! flogi ) {
821                 DBGC ( fcoe, "FCoE %s received ELS response missing FLOGI\n",
822                        fcoe->netdev->name );
823                 return -EINVAL;
824         }
825         if ( ! mac_address ) {
826                 DBGC ( fcoe, "FCoE %s received ELS response missing MAC "
827                        "address\n", fcoe->netdev->name );
828                 return -EINVAL;
829         }
830
831         /* Record local MAC address */
832         memcpy ( fcoe->local_mac, mac_address->mac, sizeof ( fcoe->local_mac ));
833         DBGC ( fcoe, "FCoE %s using local MAC %s\n",
834                fcoe->netdev->name, eth_ntoa ( fcoe->local_mac ) );
835
836         /* Hand off via transport interface */
837         frame = &flogi->fc;
838         frame_len = ( ( flogi->len * 4 ) - offsetof ( typeof ( *flogi ), fc ) );
839         if ( ( rc = xfer_deliver_raw ( &fcoe->transport, frame,
840                                        frame_len ) ) != 0 ) {
841                 DBGC ( fcoe, "FCoE %s could not deliver FIP FLOGI frame: %s\n",
842                        fcoe->netdev->name, strerror ( rc ) );
843                 return rc;
844         }
845
846         return 0;
847 }
848
849 /**
850  * Send FIP keepalive
851  *
852  * @v fcoe              FCoE port
853  * @ret rc              Return status code
854  */
855 static int fcoe_fip_tx_keepalive ( struct fcoe_port *fcoe ) {
856         struct io_buffer *iobuf;
857         struct {
858                 struct fip_header hdr;
859                 struct fip_mac_address mac_address;
860         } __attribute__ (( packed )) *keepalive;
861         int rc;
862
863         /* Allocate I/O buffer */
864         iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *keepalive ) );
865         if ( ! iobuf )
866                 return -ENOMEM;
867         iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
868
869         /* Construct keepalive */
870         keepalive = iob_put ( iobuf, sizeof ( *keepalive ) );
871         memset ( keepalive, 0, sizeof ( *keepalive ) );
872         keepalive->hdr.version = FIP_VERSION;
873         keepalive->hdr.code = htons ( FIP_CODE_MAINTAIN );
874         keepalive->hdr.subcode = FIP_MAINTAIN_KEEP_ALIVE;
875         keepalive->hdr.len =    htons ( ( sizeof ( *keepalive ) -
876                                           sizeof ( keepalive->hdr ) ) / 4 );
877         keepalive->mac_address.type = FIP_MAC_ADDRESS;
878         keepalive->mac_address.len =
879                 ( sizeof ( keepalive->mac_address ) / 4 );
880         memcpy ( keepalive->mac_address.mac, fcoe->netdev->ll_addr,
881                  sizeof ( keepalive->mac_address.mac ) );
882
883         /* Send keepalive */
884         if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev,
885                              &fip_protocol, fcoe->fcf_mac,
886                              fcoe->netdev->ll_addr ) ) != 0 ) {
887                 DBGC ( fcoe, "FCoE %s could not send keepalive: %s\n",
888                        fcoe->netdev->name, strerror ( rc ) );
889                 return rc;
890         }
891
892         return 0;
893 }
894
895 /** A FIP handler */
896 struct fip_handler {
897         /** Protocol code */
898         uint16_t code;
899         /** Protocol subcode */
900         uint8_t subcode;
901         /**
902          * Receive FIP packet
903          *
904          * @v fcoe              FCoE port
905          * @v descs             Descriptor list
906          * @v flags             Flags
907          * @ret rc              Return status code
908          */
909         int ( * rx ) ( struct fcoe_port *fcoe, struct fip_descriptors *descs,
910                        unsigned int flags );
911 };
912
913 /** FIP handlers */
914 static struct fip_handler fip_handlers[] = {
915         { FIP_CODE_VLAN, FIP_VLAN_NOTIFY,
916           fcoe_fip_rx_vlan },
917         { FIP_CODE_DISCOVERY, FIP_DISCOVERY_ADVERTISE,
918           fcoe_fip_rx_advertisement },
919         { FIP_CODE_ELS, FIP_ELS_RESPONSE,
920           fcoe_fip_rx_els_response },
921 };
922
923 /**
924  * Process incoming FIP packets
925  *
926  * @v iobuf             I/O buffer
927  * @v netdev            Network device
928  * @v ll_dest           Link-layer destination address
929  * @v ll_source         Link-layer source address
930  * @v flags             Packet flags
931  * @ret rc              Return status code
932  */
933 static int fcoe_fip_rx ( struct io_buffer *iobuf,
934                          struct net_device *netdev,
935                          const void *ll_dest,
936                          const void *ll_source __unused,
937                          unsigned int flags __unused ) {
938         struct fip_header *fiphdr = iobuf->data;
939         struct fip_descriptors descs;
940         struct fip_handler *handler;
941         struct fcoe_port *fcoe;
942         unsigned int i;
943         int rc;
944
945         /* Identify FCoE port */
946         if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) {
947                 DBG ( "FCoE received FIP frame for net device %s missing FCoE "
948                       "port\n", netdev->name );
949                 rc = -ENOTCONN;
950                 goto done;
951         }
952
953         /* Discard packets not destined for us */
954         if ( ( memcmp ( fcoe->netdev->ll_addr, ll_dest, ETH_ALEN ) != 0 ) &&
955              ( memcmp ( all_fcoe_macs, ll_dest,
956                         sizeof ( all_fcoe_macs ) ) != 0 ) &&
957              ( memcmp ( all_enode_macs, ll_dest,
958                         sizeof ( all_enode_macs ) ) != 0 ) ) {
959                 DBGC2 ( fcoe, "FCoE %s ignoring FIP packet for %s\n",
960                         fcoe->netdev->name, eth_ntoa ( ll_dest ) );
961                 rc = -ENOTCONN;
962                 goto done;
963         }
964
965         /* Parse FIP packet */
966         if ( ( rc = fcoe_fip_parse ( fcoe, fiphdr, iob_len ( iobuf ),
967                                      &descs ) ) != 0 )
968                 goto done;
969
970         /* Find a suitable handler */
971         for ( i = 0 ; i < ( sizeof ( fip_handlers ) /
972                             sizeof ( fip_handlers[0] ) ) ; i++ ) {
973                 handler = &fip_handlers[i];
974                 if ( ( handler->code == ntohs ( fiphdr->code ) ) &&
975                      ( handler->subcode == fiphdr->subcode ) ) {
976                         rc = handler->rx ( fcoe, &descs,
977                                            ntohs ( fiphdr->flags ) );
978                         goto done;
979                 }
980         }
981         DBGC ( fcoe, "FCoE %s received unsupported FIP code %04x.%02x\n",
982                fcoe->netdev->name, ntohs ( fiphdr->code ), fiphdr->subcode );
983         rc = -ENOTSUP;
984
985  done:
986         free_iob ( iobuf );
987         return rc;
988 }
989
990 /******************************************************************************
991  *
992  * FCoE ports
993  *
994  ******************************************************************************
995  */
996
997 /**
998  * Handle FCoE timer expiry
999  *
1000  * @v timer             FIP timer
1001  * @v over              Timer expired
1002  */
1003 static void fcoe_expired ( struct retry_timer *timer, int over __unused ) {
1004         struct fcoe_port *fcoe =
1005                 container_of ( timer, struct fcoe_port, timer );
1006         int rc;
1007
1008         /* Sanity check */
1009         assert ( fcoe->flags & FCOE_HAVE_NETWORK );
1010
1011         /* Increment the timeout counter */
1012         fcoe->timeouts++;
1013
1014         if ( vlan_can_be_trunk ( fcoe->netdev ) &&
1015              ! ( fcoe->flags & FCOE_VLAN_TIMED_OUT ) ) {
1016
1017                 /* If we have already found a VLAN, send infrequent
1018                  * VLAN requests, in case VLAN information changes.
1019                  */
1020                 if ( fcoe->flags & FCOE_VLAN_FOUND ) {
1021                         fcoe->flags &= ~FCOE_VLAN_FOUND;
1022                         fcoe->timeouts = 0;
1023                         start_timer_fixed ( &fcoe->timer,
1024                                             FCOE_VLAN_POLL_DELAY );
1025                         fcoe_fip_tx_vlan ( fcoe );
1026                         return;
1027                 }
1028
1029                 /* If we have not yet found a VLAN, and we have not
1030                  * yet timed out and given up on finding one, then
1031                  * send a VLAN request and wait.
1032                  */
1033                 if ( fcoe->timeouts <= FCOE_MAX_VLAN_REQUESTS ) {
1034                         start_timer_fixed ( &fcoe->timer,
1035                                             FCOE_VLAN_RETRY_DELAY );
1036                         fcoe_fip_tx_vlan ( fcoe );
1037                         return;
1038                 }
1039
1040                 /* We have timed out waiting for a VLAN; proceed to
1041                  * FIP discovery.
1042                  */
1043                 fcoe->flags |= FCOE_VLAN_TIMED_OUT;
1044                 fcoe->timeouts = 0;
1045                 DBGC ( fcoe, "FCoE %s giving up on VLAN discovery\n",
1046                        fcoe->netdev->name );
1047                 start_timer_nodelay ( &fcoe->timer );
1048
1049         } else if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) {
1050
1051                 /* If we have not yet found a FIP-capable forwarder,
1052                  * and we have not yet timed out and given up on
1053                  * finding one, then send a FIP solicitation and wait.
1054                  */
1055                 start_timer_fixed ( &fcoe->timer, FCOE_FIP_RETRY_DELAY );
1056                 if ( ( ! ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ) &&
1057                      ( fcoe->timeouts <= FCOE_MAX_FIP_SOLICITATIONS ) ) {
1058                         fcoe_fip_tx_solicitation ( fcoe );
1059                         return;
1060                 }
1061
1062                 /* Attach Fibre Channel port */
1063                 if ( ( rc = fc_port_open ( &fcoe->transport, &fcoe->node_wwn.fc,
1064                                            &fcoe->port_wwn.fc,
1065                                            fcoe->netdev->name ) ) != 0 ) {
1066                         DBGC ( fcoe, "FCoE %s could not create FC port: %s\n",
1067                                fcoe->netdev->name, strerror ( rc ) );
1068                         /* We will try again on the next timer expiry */
1069                         return;
1070                 }
1071                 stop_timer ( &fcoe->timer );
1072
1073                 /* Either we have found a FIP-capable forwarder, or we
1074                  * have timed out and will fall back to pre-FIP mode.
1075                  */
1076                 fcoe->flags |= FCOE_HAVE_FCF;
1077                 fcoe->timeouts = 0;
1078                 DBGC ( fcoe, "FCoE %s using %sFIP FCF %s\n", fcoe->netdev->name,
1079                        ( ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ? "" : "non-" ),
1080                        eth_ntoa ( fcoe->fcf_mac ) );
1081
1082                 /* Start sending keepalives if applicable */
1083                 if ( fcoe->keepalive )
1084                         start_timer_nodelay ( &fcoe->timer );
1085
1086                 /* Send notification of window change */
1087                 xfer_window_changed ( &fcoe->transport );
1088
1089         } else {
1090
1091                 /* Send keepalive */
1092                 start_timer_fixed ( &fcoe->timer,
1093                               ( ( fcoe->keepalive * TICKS_PER_SEC ) / 1000 ) );
1094                 fcoe_fip_tx_keepalive ( fcoe );
1095
1096                 /* Abandon FCF if we have not seen its advertisements */
1097                 if ( fcoe->timeouts > FCOE_MAX_FIP_MISSING_KEEPALIVES ) {
1098                         DBGC ( fcoe, "FCoE %s abandoning FCF %s\n",
1099                                fcoe->netdev->name, eth_ntoa ( fcoe->fcf_mac ));
1100                         fcoe_reset ( fcoe );
1101                 }
1102         }
1103 }
1104
1105 /**
1106  * Create FCoE port
1107  *
1108  * @v netdev            Network device
1109  * @ret rc              Return status code
1110  */
1111 static int fcoe_probe ( struct net_device *netdev ) {
1112         struct ll_protocol *ll_protocol = netdev->ll_protocol;
1113         struct fcoe_port *fcoe;
1114         int rc;
1115
1116         /* Sanity check */
1117         if ( ll_protocol->ll_proto != htons ( ARPHRD_ETHER ) ) {
1118                 /* Not an error; simply skip this net device */
1119                 DBG ( "FCoE skipping non-Ethernet device %s\n", netdev->name );
1120                 rc = 0;
1121                 goto err_non_ethernet;
1122         }
1123
1124         /* Allocate and initialise structure */
1125         fcoe = zalloc ( sizeof ( *fcoe ) );
1126         if ( ! fcoe ) {
1127                 rc = -ENOMEM;
1128                 goto err_zalloc;
1129         }
1130         ref_init ( &fcoe->refcnt, NULL );
1131         intf_init ( &fcoe->transport, &fcoe_transport_desc, &fcoe->refcnt );
1132         timer_init ( &fcoe->timer, fcoe_expired, &fcoe->refcnt );
1133         fcoe->netdev = netdev_get ( netdev );
1134
1135         /* Construct node and port names */
1136         fcoe->node_wwn.fcoe.authority = htons ( FCOE_AUTHORITY_IEEE );
1137         memcpy ( &fcoe->node_wwn.fcoe.mac, netdev->ll_addr,
1138                  sizeof ( fcoe->node_wwn.fcoe.mac ) );
1139         fcoe->port_wwn.fcoe.authority = htons ( FCOE_AUTHORITY_IEEE_EXTENDED );
1140         memcpy ( &fcoe->port_wwn.fcoe.mac, netdev->ll_addr,
1141                  sizeof ( fcoe->port_wwn.fcoe.mac ) );
1142
1143         DBGC ( fcoe, "FCoE %s is %s", fcoe->netdev->name,
1144                fc_ntoa ( &fcoe->node_wwn.fc ) );
1145         DBGC ( fcoe, " port %s\n", fc_ntoa ( &fcoe->port_wwn.fc ) );
1146
1147         /* Transfer reference to port list */
1148         list_add ( &fcoe->list, &fcoe_ports );
1149         return 0;
1150
1151         netdev_put ( fcoe->netdev );
1152  err_zalloc:
1153  err_non_ethernet:
1154         return rc;
1155 }
1156
1157 /**
1158  * Handle FCoE port device or link state change
1159  *
1160  * @v netdev            Network device
1161  */
1162 static void fcoe_notify ( struct net_device *netdev ) {
1163         struct fcoe_port *fcoe;
1164
1165         /* Sanity check */
1166         if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) {
1167                 DBG ( "FCoE notification for net device %s missing FCoE "
1168                       "port\n", netdev->name );
1169                 return;
1170         }
1171
1172         /* Reset the FCoE link if necessary */
1173         if ( ! ( netdev_is_open ( netdev ) &&
1174                  netdev_link_ok ( netdev ) &&
1175                  ( fcoe->flags & FCOE_HAVE_NETWORK ) ) ) {
1176                 fcoe_reset ( fcoe );
1177         }
1178 }
1179
1180 /**
1181  * Destroy FCoE port
1182  *
1183  * @v netdev            Network device
1184  */
1185 static void fcoe_remove ( struct net_device *netdev ) {
1186         struct fcoe_port *fcoe;
1187
1188         /* Sanity check */
1189         if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) {
1190                 DBG ( "FCoE removal of net device %s missing FCoE port\n",
1191                       netdev->name );
1192                 return;
1193         }
1194
1195         /* Close FCoE device */
1196         fcoe_close ( fcoe, 0 );
1197 }
1198
1199 /** FCoE driver */
1200 struct net_driver fcoe_driver __net_driver = {
1201         .name = "FCoE",
1202         .probe = fcoe_probe,
1203         .notify = fcoe_notify,
1204         .remove = fcoe_remove,
1205 };
1206
1207 /** FCoE protocol */
1208 struct net_protocol fcoe_protocol __net_protocol = {
1209         .name = "FCoE",
1210         .net_proto = htons ( ETH_P_FCOE ),
1211         .rx = fcoe_rx,
1212 };
1213
1214 /** FIP protocol */
1215 struct net_protocol fip_protocol __net_protocol = {
1216         .name = "FIP",
1217         .net_proto = htons ( ETH_P_FIP ),
1218         .rx = fcoe_fip_rx,
1219 };
1220
1221 /** Human-readable message for CRC errors
1222  *
1223  * It seems as though several drivers neglect to strip the Ethernet
1224  * CRC, which will cause the FCoE footer to be misplaced and result
1225  * (coincidentally) in an "invalid CRC" error from FCoE.
1226  */
1227 struct errortab fcoe_errors[] __errortab = {
1228         __einfo_errortab ( EINFO_EINVAL_CRC ),
1229 };