2 * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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
20 FILE_LICENCE ( GPL2_OR_LATER );
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>
42 #include <ipxe/fcoe.h>
50 FEATURE ( FEATURE_PROTOCOL, "FCoE", DHCP_EB_FEATURE_FCOE, 1 );
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" )
68 /** Reference count */
70 /** List of FCoE ports */
71 struct list_head list;
72 /** Transport interface */
73 struct interface transport;
75 struct net_device *netdev;
78 union fcoe_name node_wwn;
80 union fcoe_name port_wwn;
82 /** FIP retransmission timer */
83 struct retry_timer timer;
84 /** FIP timeout counter */
85 unsigned int timeouts;
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];
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,
114 struct net_protocol fcoe_protocol __net_protocol;
115 struct net_protocol fip_protocol __net_protocol;
117 /** FCoE All-FCoE-MACs address */
118 static uint8_t all_fcoe_macs[ETH_ALEN] =
119 { 0x01, 0x10, 0x18, 0x01, 0x00, 0x00 };
121 /** FCoE All-ENode-MACs address */
122 static uint8_t all_enode_macs[ETH_ALEN] =
123 { 0x01, 0x10, 0x18, 0x01, 0x00, 0x01 };
125 /** FCoE All-FCF-MACs address */
126 static uint8_t all_fcf_macs[ETH_ALEN] =
127 { 0x01, 0x10, 0x18, 0x01, 0x00, 0x02 };
129 /** Default FCoE forwarded MAC address */
130 static uint8_t default_fcf_mac[ETH_ALEN] =
131 { 0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe };
133 /** Maximum number of VLAN requests before giving up on VLAN discovery */
134 #define FCOE_MAX_VLAN_REQUESTS 2
136 /** Delay between retrying VLAN requests */
137 #define FCOE_VLAN_RETRY_DELAY ( TICKS_PER_SEC )
139 /** Delay between retrying polling VLAN requests */
140 #define FCOE_VLAN_POLL_DELAY ( 30 * TICKS_PER_SEC )
142 /** Maximum number of FIP solicitations before giving up on FIP */
143 #define FCOE_MAX_FIP_SOLICITATIONS 2
145 /** Delay between retrying FIP solicitations */
146 #define FCOE_FIP_RETRY_DELAY ( TICKS_PER_SEC )
148 /** Maximum number of missing discovery advertisements */
149 #define FCOE_MAX_FIP_MISSING_KEEPALIVES 4
151 /** List of FCoE ports */
152 static LIST_HEAD ( fcoe_ports );
154 /******************************************************************************
158 ******************************************************************************
162 * Identify FCoE port by network device
164 * @v netdev Network device
165 * @ret fcoe FCoE port, or NULL
167 static struct fcoe_port * fcoe_demux ( struct net_device *netdev ) {
168 struct fcoe_port *fcoe;
170 list_for_each_entry ( fcoe, &fcoe_ports, list ) {
171 if ( fcoe->netdev == netdev )
182 static void fcoe_reset ( struct fcoe_port *fcoe ) {
184 /* Detach FC port, if any */
185 intf_restart ( &fcoe->transport, -ECANCELED );
187 /* Reset any FIP state */
188 stop_timer ( &fcoe->timer );
191 fcoe->priority = ( FIP_LOWEST_PRIORITY + 1 );
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 ) );
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" ) );
208 /* Send notification of window change */
209 xfer_window_changed ( &fcoe->transport );
213 * Transmit FCoE packet
216 * @v iobuf I/O buffer
217 * @v meta Data transfer metadata
218 * @ret rc Return status code
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;
231 struct net_protocol *net_protocol;
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 ) ) {
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 );
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 ) );
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;
264 htons ( ( iob_len ( iobuf ) - sizeof ( *fiphdr ) ) / 4);
265 fiphdr->flags = ( ( fcoe->flags & FCOE_FCF_ALLOWS_SPMA ) ?
266 htons ( FIP_SP ) : htons ( FIP_FP ) );
268 /* Send as FIP packet from netdev's own MAC address */
269 net_protocol = &fip_protocol;
270 ll_source = fcoe->netdev->ll_addr;
275 crc = crc32_le ( ~((uint32_t)0), iobuf->data,
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 );
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 );
291 /* Send as FCoE packet from FCoE MAC address */
292 net_protocol = &fcoe_protocol;
293 ll_source = fcoe->local_mac;
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 ) );
310 * Allocate FCoE I/O buffer
312 * @v len Payload length
313 * @ret iobuf I/O buffer, or NULL
315 static struct io_buffer * fcoe_alloc_iob ( struct fcoe_port *fcoe __unused,
317 struct io_buffer *iobuf;
319 iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( struct fcoe_header ) +
320 len + sizeof ( struct fcoe_footer ) );
322 iob_reserve ( iobuf, ( MAX_LL_HEADER_LEN +
323 sizeof ( struct fcoe_header ) ) );
329 * Process incoming FCoE packets
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
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;
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 );
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 ) );
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;
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 ) );
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;
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 );
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 );
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 );
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 ) );
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 ) );
428 * Check FCoE flow control window
431 * @ret len Length of window
433 static size_t fcoe_window ( struct fcoe_port *fcoe ) {
434 return ( ( fcoe->flags & FCOE_HAVE_FCF ) ? ~( ( size_t ) 0 ) : 0 );
441 * @v rc Reason for close
443 static void fcoe_close ( struct fcoe_port *fcoe, int rc ) {
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 );
453 * Identify device underlying FCoE port
456 * @ret device Underlying device
458 static struct device * fcoe_identify_device ( struct fcoe_port *fcoe ) {
459 return fcoe->netdev->dev;
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 ),
472 /** FCoE transport interface descriptor */
473 static struct interface_descriptor fcoe_transport_desc =
474 INTF_DESC ( struct fcoe_port, transport, fcoe_transport_op );
476 /******************************************************************************
480 ******************************************************************************
484 * Parse FIP packet into descriptor set
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
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;
498 unsigned int desc_type;
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 );
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 );
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 ) {
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 );
530 if ( ( desc_offset + desc_len ) > descs_len ) {
531 DBGC ( fcoe, "FCoE %s descriptor overrun\n",
532 fcoe->netdev->name );
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;
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 );
553 /* Ignore non-critical descriptors that we cannot understand */
560 * Send FIP VLAN request
563 * @ret rc Return status code
565 static int fcoe_fip_tx_vlan ( struct fcoe_port *fcoe ) {
566 struct io_buffer *iobuf;
568 struct fip_header hdr;
569 struct fip_mac_address mac_address;
570 } __attribute__ (( packed )) *request;
573 /* Allocate I/O buffer */
574 iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *request ) );
577 iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
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 ) );
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 ) );
606 * Handle received FIP VLAN notification
609 * @v descs Descriptor list
611 * @ret rc Return status code
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 );
622 if ( ! mac_address ) {
623 DBGC ( fcoe, "FCoE %s received VLAN notification missing MAC "
624 "address\n", fcoe->netdev->name );
628 DBGC ( fcoe, "FCoE %s received VLAN notification missing VLAN "
629 "tag\n", fcoe->netdev->name );
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 ) );
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.
648 fcoe->flags |= FCOE_VLAN_FOUND;
654 * Send FIP discovery solicitation
657 * @ret rc Return status code
659 static int fcoe_fip_tx_solicitation ( struct fcoe_port *fcoe ) {
660 struct io_buffer *iobuf;
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;
669 /* Allocate I/O buffer */
670 iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *solicitation ) );
673 iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
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 ) );
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 ) );
713 * Handle received FIP discovery advertisement
716 * @v descs Descriptor list
718 * @ret rc Return status code
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 );
729 DBGC ( fcoe, "FCoE %s received advertisement missing "
730 "priority\n", fcoe->netdev->name );
733 if ( ! mac_address ) {
734 DBGC ( fcoe, "FCoE %s received advertisement missing MAC "
735 "address\n", fcoe->netdev->name );
739 DBGC ( fcoe, "FCoE %s received advertisement missing FKA ADV "
740 "period\n", fcoe->netdev->name );
744 if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) {
746 /* We are soliciting for an FCF. Store the highest
747 * (i.e. lowest-valued) priority solicited
748 * advertisement that we receive.
750 if ( ( ( flags & ( FIP_A | FIP_S | FIP_F ) ) ==
751 ( FIP_A | FIP_S | FIP_F ) ) &&
752 ( priority->priority < fcoe->priority ) ) {
754 fcoe->flags |= FCOE_HAVE_FIP_FCF;
755 fcoe->priority = priority->priority;
756 if ( fka_adv_p->flags & FIP_NO_KEEPALIVE ) {
759 fcoe->keepalive = ntohl ( fka_adv_p->period );
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 ),
769 if ( fcoe->keepalive ) {
770 DBGC ( fcoe, ", FKA ADV %dms",
773 DBGC ( fcoe, ", %cPMA)\n",
774 ( ( fcoe->flags & FCOE_FCF_ALLOWS_SPMA ) ?
778 } else if ( fcoe->flags & FCOE_HAVE_FIP_FCF ) {
780 /* We are checking that the FCF remains alive. Reset
781 * the timeout counter if this is an advertisement
782 * from our forwarder.
784 if ( memcmp ( fcoe->fcf_mac, mac_address->mac,
785 sizeof ( fcoe->fcf_mac ) ) == 0 ) {
791 /* We are operating in non-FIP mode and have received
792 * a FIP advertisement. Reset the link in order to
803 * Handle received FIP ELS response
806 * @v descs Descriptor list
808 * @ret rc Return status code
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 );
821 DBGC ( fcoe, "FCoE %s received ELS response missing FLOGI\n",
822 fcoe->netdev->name );
825 if ( ! mac_address ) {
826 DBGC ( fcoe, "FCoE %s received ELS response missing MAC "
827 "address\n", fcoe->netdev->name );
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 ) );
836 /* Hand off via transport interface */
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 ) );
853 * @ret rc Return status code
855 static int fcoe_fip_tx_keepalive ( struct fcoe_port *fcoe ) {
856 struct io_buffer *iobuf;
858 struct fip_header hdr;
859 struct fip_mac_address mac_address;
860 } __attribute__ (( packed )) *keepalive;
863 /* Allocate I/O buffer */
864 iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *keepalive ) );
867 iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
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 ) );
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 ) );
899 /** Protocol subcode */
905 * @v descs Descriptor list
907 * @ret rc Return status code
909 int ( * rx ) ( struct fcoe_port *fcoe, struct fip_descriptors *descs,
910 unsigned int flags );
914 static struct fip_handler fip_handlers[] = {
915 { FIP_CODE_VLAN, FIP_VLAN_NOTIFY,
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 },
924 * Process incoming FIP packets
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
933 static int fcoe_fip_rx ( struct io_buffer *iobuf,
934 struct net_device *netdev,
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;
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 );
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 ) );
965 /* Parse FIP packet */
966 if ( ( rc = fcoe_fip_parse ( fcoe, fiphdr, iob_len ( iobuf ),
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 ) );
981 DBGC ( fcoe, "FCoE %s received unsupported FIP code %04x.%02x\n",
982 fcoe->netdev->name, ntohs ( fiphdr->code ), fiphdr->subcode );
990 /******************************************************************************
994 ******************************************************************************
998 * Handle FCoE timer expiry
1000 * @v timer FIP timer
1001 * @v over Timer expired
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 );
1009 assert ( fcoe->flags & FCOE_HAVE_NETWORK );
1011 /* Increment the timeout counter */
1014 if ( vlan_can_be_trunk ( fcoe->netdev ) &&
1015 ! ( fcoe->flags & FCOE_VLAN_TIMED_OUT ) ) {
1017 /* If we have already found a VLAN, send infrequent
1018 * VLAN requests, in case VLAN information changes.
1020 if ( fcoe->flags & FCOE_VLAN_FOUND ) {
1021 fcoe->flags &= ~FCOE_VLAN_FOUND;
1023 start_timer_fixed ( &fcoe->timer,
1024 FCOE_VLAN_POLL_DELAY );
1025 fcoe_fip_tx_vlan ( fcoe );
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.
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 );
1040 /* We have timed out waiting for a VLAN; proceed to
1043 fcoe->flags |= FCOE_VLAN_TIMED_OUT;
1045 DBGC ( fcoe, "FCoE %s giving up on VLAN discovery\n",
1046 fcoe->netdev->name );
1047 start_timer_nodelay ( &fcoe->timer );
1049 } else if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) {
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.
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 );
1062 /* Attach Fibre Channel port */
1063 if ( ( rc = fc_port_open ( &fcoe->transport, &fcoe->node_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 */
1071 stop_timer ( &fcoe->timer );
1073 /* Either we have found a FIP-capable forwarder, or we
1074 * have timed out and will fall back to pre-FIP mode.
1076 fcoe->flags |= FCOE_HAVE_FCF;
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 ) );
1082 /* Start sending keepalives if applicable */
1083 if ( fcoe->keepalive )
1084 start_timer_nodelay ( &fcoe->timer );
1086 /* Send notification of window change */
1087 xfer_window_changed ( &fcoe->transport );
1091 /* Send keepalive */
1092 start_timer_fixed ( &fcoe->timer,
1093 ( ( fcoe->keepalive * TICKS_PER_SEC ) / 1000 ) );
1094 fcoe_fip_tx_keepalive ( fcoe );
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 );
1108 * @v netdev Network device
1109 * @ret rc Return status code
1111 static int fcoe_probe ( struct net_device *netdev ) {
1112 struct ll_protocol *ll_protocol = netdev->ll_protocol;
1113 struct fcoe_port *fcoe;
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 );
1121 goto err_non_ethernet;
1124 /* Allocate and initialise structure */
1125 fcoe = zalloc ( sizeof ( *fcoe ) );
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 );
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 ) );
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 ) );
1147 /* Transfer reference to port list */
1148 list_add ( &fcoe->list, &fcoe_ports );
1151 netdev_put ( fcoe->netdev );
1158 * Handle FCoE port device or link state change
1160 * @v netdev Network device
1162 static void fcoe_notify ( struct net_device *netdev ) {
1163 struct fcoe_port *fcoe;
1166 if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) {
1167 DBG ( "FCoE notification for net device %s missing FCoE "
1168 "port\n", netdev->name );
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 );
1183 * @v netdev Network device
1185 static void fcoe_remove ( struct net_device *netdev ) {
1186 struct fcoe_port *fcoe;
1189 if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) {
1190 DBG ( "FCoE removal of net device %s missing FCoE port\n",
1195 /* Close FCoE device */
1196 fcoe_close ( fcoe, 0 );
1200 struct net_driver fcoe_driver __net_driver = {
1202 .probe = fcoe_probe,
1203 .notify = fcoe_notify,
1204 .remove = fcoe_remove,
1207 /** FCoE protocol */
1208 struct net_protocol fcoe_protocol __net_protocol = {
1210 .net_proto = htons ( ETH_P_FCOE ),
1215 struct net_protocol fip_protocol __net_protocol = {
1217 .net_proto = htons ( ETH_P_FIP ),
1221 /** Human-readable message for CRC errors
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.
1227 struct errortab fcoe_errors[] __errortab = {
1228 __einfo_errortab ( EINFO_EINVAL_CRC ),