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