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
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.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL
);
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>
46 #include <ipxe/fcoe.h>
54 FEATURE ( FEATURE_PROTOCOL
, "FCoE", DHCP_EB_FEATURE_FCOE
, 1 );
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" )
72 /** Reference count */
74 /** List of FCoE ports */
75 struct list_head list
;
76 /** Transport interface */
77 struct interface transport
;
79 struct net_device
*netdev
;
82 union fcoe_name node_wwn
;
84 union fcoe_name port_wwn
;
86 /** FIP retransmission timer */
87 struct retry_timer timer
;
88 /** FIP timeout counter */
89 unsigned int timeouts
;
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
];
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,
118 struct net_protocol fcoe_protocol __net_protocol
;
119 struct net_protocol fip_protocol __net_protocol
;
121 /** FCoE All-FCoE-MACs address */
122 static uint8_t all_fcoe_macs
[ETH_ALEN
] =
123 { 0x01, 0x10, 0x18, 0x01, 0x00, 0x00 };
125 /** FCoE All-ENode-MACs address */
126 static uint8_t all_enode_macs
[ETH_ALEN
] =
127 { 0x01, 0x10, 0x18, 0x01, 0x00, 0x01 };
129 /** FCoE All-FCF-MACs address */
130 static uint8_t all_fcf_macs
[ETH_ALEN
] =
131 { 0x01, 0x10, 0x18, 0x01, 0x00, 0x02 };
133 /** Default FCoE forwarded MAC address */
134 static uint8_t default_fcf_mac
[ETH_ALEN
] =
135 { 0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe };
137 /** Maximum number of VLAN requests before giving up on VLAN discovery */
138 #define FCOE_MAX_VLAN_REQUESTS 2
140 /** Delay between retrying VLAN requests */
141 #define FCOE_VLAN_RETRY_DELAY ( TICKS_PER_SEC )
143 /** Delay between retrying polling VLAN requests */
144 #define FCOE_VLAN_POLL_DELAY ( 30 * TICKS_PER_SEC )
146 /** Maximum number of FIP solicitations before giving up on FIP */
147 #define FCOE_MAX_FIP_SOLICITATIONS 2
149 /** Delay between retrying FIP solicitations */
150 #define FCOE_FIP_RETRY_DELAY ( TICKS_PER_SEC )
152 /** Maximum number of missing discovery advertisements */
153 #define FCOE_MAX_FIP_MISSING_KEEPALIVES 4
155 /** List of FCoE ports */
156 static LIST_HEAD ( fcoe_ports
);
158 /******************************************************************************
162 ******************************************************************************
166 * Identify FCoE port by network device
168 * @v netdev Network device
169 * @ret fcoe FCoE port, or NULL
171 static struct fcoe_port
* fcoe_demux ( struct net_device
*netdev
) {
172 struct fcoe_port
*fcoe
;
174 list_for_each_entry ( fcoe
, &fcoe_ports
, list
) {
175 if ( fcoe
->netdev
== netdev
)
186 static void fcoe_reset ( struct fcoe_port
*fcoe
) {
188 /* Detach FC port, if any */
189 intf_restart ( &fcoe
->transport
, -ECANCELED
);
191 /* Reset any FIP state */
192 stop_timer ( &fcoe
->timer
);
195 fcoe
->priority
= ( FIP_LOWEST_PRIORITY
+ 1 );
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
) );
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" ) );
212 /* Send notification of window change */
213 xfer_window_changed ( &fcoe
->transport
);
217 * Transmit FCoE packet
220 * @v iobuf I/O buffer
221 * @v meta Data transfer metadata
222 * @ret rc Return status code
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
;
235 struct net_protocol
*net_protocol
;
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
) ) {
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 );
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
) );
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
;
268 htons ( ( iob_len ( iobuf
) - sizeof ( *fiphdr
) ) / 4);
269 fiphdr
->flags
= ( ( fcoe
->flags
& FCOE_FCF_ALLOWS_SPMA
) ?
270 htons ( FIP_SP
) : htons ( FIP_FP
) );
272 /* Send as FIP packet from netdev's own MAC address */
273 net_protocol
= &fip_protocol
;
274 ll_source
= fcoe
->netdev
->ll_addr
;
279 crc
= crc32_le ( ~((uint32_t)0), iobuf
->data
,
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
);
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
);
295 /* Send as FCoE packet from FCoE MAC address */
296 net_protocol
= &fcoe_protocol
;
297 ll_source
= fcoe
->local_mac
;
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
) );
314 * Allocate FCoE I/O buffer
316 * @v len Payload length
317 * @ret iobuf I/O buffer, or NULL
319 static struct io_buffer
* fcoe_alloc_iob ( struct fcoe_port
*fcoe __unused
,
321 struct io_buffer
*iobuf
;
323 iobuf
= alloc_iob ( MAX_LL_HEADER_LEN
+ sizeof ( struct fcoe_header
) +
324 len
+ sizeof ( struct fcoe_footer
) );
326 iob_reserve ( iobuf
, ( MAX_LL_HEADER_LEN
+
327 sizeof ( struct fcoe_header
) ) );
333 * Process incoming FCoE packets
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
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
;
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
);
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
) );
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
;
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
) );
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
;
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
);
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
);
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
);
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
) );
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
) );
432 * Check FCoE flow control window
435 * @ret len Length of window
437 static size_t fcoe_window ( struct fcoe_port
*fcoe
) {
438 return ( ( fcoe
->flags
& FCOE_HAVE_FCF
) ?
~( ( size_t ) 0 ) : 0 );
445 * @v rc Reason for close
447 static void fcoe_close ( struct fcoe_port
*fcoe
, int rc
) {
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
);
457 * Identify device underlying FCoE port
460 * @ret device Underlying device
462 static struct device
* fcoe_identify_device ( struct fcoe_port
*fcoe
) {
463 return fcoe
->netdev
->dev
;
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
),
476 /** FCoE transport interface descriptor */
477 static struct interface_descriptor fcoe_transport_desc
=
478 INTF_DESC ( struct fcoe_port
, transport
, fcoe_transport_op
);
480 /******************************************************************************
484 ******************************************************************************
488 * Parse FIP packet into descriptor set
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
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
;
502 unsigned int desc_type
;
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
);
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
);
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
) {
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
);
534 if ( ( desc_offset
+ desc_len
) > descs_len
) {
535 DBGC ( fcoe
, "FCoE %s descriptor overrun\n",
536 fcoe
->netdev
->name
);
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
;
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
);
557 /* Ignore non-critical descriptors that we cannot understand */
564 * Send FIP VLAN request
567 * @ret rc Return status code
569 static int fcoe_fip_tx_vlan ( struct fcoe_port
*fcoe
) {
570 struct io_buffer
*iobuf
;
572 struct fip_header hdr
;
573 struct fip_mac_address mac_address
;
574 } __attribute__ (( packed
)) *request
;
577 /* Allocate I/O buffer */
578 iobuf
= alloc_iob ( MAX_LL_HEADER_LEN
+ sizeof ( *request
) );
581 iob_reserve ( iobuf
, MAX_LL_HEADER_LEN
);
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
) );
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
) );
610 * Handle received FIP VLAN notification
613 * @v descs Descriptor list
615 * @ret rc Return status code
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
);
626 if ( ! mac_address
) {
627 DBGC ( fcoe
, "FCoE %s received VLAN notification missing MAC "
628 "address\n", fcoe
->netdev
->name
);
632 DBGC ( fcoe
, "FCoE %s received VLAN notification missing VLAN "
633 "tag\n", fcoe
->netdev
->name
);
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
) );
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.
652 fcoe
->flags
|= FCOE_VLAN_FOUND
;
658 * Send FIP discovery solicitation
661 * @ret rc Return status code
663 static int fcoe_fip_tx_solicitation ( struct fcoe_port
*fcoe
) {
664 struct io_buffer
*iobuf
;
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
;
673 /* Allocate I/O buffer */
674 iobuf
= alloc_iob ( MAX_LL_HEADER_LEN
+ sizeof ( *solicitation
) );
677 iob_reserve ( iobuf
, MAX_LL_HEADER_LEN
);
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
) );
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
) );
717 * Handle received FIP discovery advertisement
720 * @v descs Descriptor list
722 * @ret rc Return status code
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
);
733 DBGC ( fcoe
, "FCoE %s received advertisement missing "
734 "priority\n", fcoe
->netdev
->name
);
737 if ( ! mac_address
) {
738 DBGC ( fcoe
, "FCoE %s received advertisement missing MAC "
739 "address\n", fcoe
->netdev
->name
);
743 DBGC ( fcoe
, "FCoE %s received advertisement missing FKA ADV "
744 "period\n", fcoe
->netdev
->name
);
748 if ( ! ( fcoe
->flags
& FCOE_HAVE_FCF
) ) {
750 /* We are soliciting for an FCF. Store the highest
751 * (i.e. lowest-valued) priority solicited
752 * advertisement that we receive.
754 if ( ( ( flags
& ( FIP_A
| FIP_S
| FIP_F
) ) ==
755 ( FIP_A
| FIP_S
| FIP_F
) ) &&
756 ( priority
->priority
< fcoe
->priority
) ) {
758 fcoe
->flags
|= FCOE_HAVE_FIP_FCF
;
759 fcoe
->priority
= priority
->priority
;
760 if ( fka_adv_p
->flags
& FIP_NO_KEEPALIVE
) {
763 fcoe
->keepalive
= ntohl ( fka_adv_p
->period
);
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
),
773 if ( fcoe
->keepalive
) {
774 DBGC ( fcoe
, ", FKA ADV %dms",
777 DBGC ( fcoe
, ", %cPMA)\n",
778 ( ( fcoe
->flags
& FCOE_FCF_ALLOWS_SPMA
) ?
782 } else if ( fcoe
->flags
& FCOE_HAVE_FIP_FCF
) {
784 /* We are checking that the FCF remains alive. Reset
785 * the timeout counter if this is an advertisement
786 * from our forwarder.
788 if ( memcmp ( fcoe
->fcf_mac
, mac_address
->mac
,
789 sizeof ( fcoe
->fcf_mac
) ) == 0 ) {
795 /* We are operating in non-FIP mode and have received
796 * a FIP advertisement. Reset the link in order to
807 * Handle received FIP ELS response
810 * @v descs Descriptor list
812 * @ret rc Return status code
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
);
825 DBGC ( fcoe
, "FCoE %s received ELS response missing FLOGI\n",
826 fcoe
->netdev
->name
);
829 if ( ! mac_address
) {
830 DBGC ( fcoe
, "FCoE %s received ELS response missing MAC "
831 "address\n", fcoe
->netdev
->name
);
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
) );
840 /* Hand off via transport interface */
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
) );
857 * @ret rc Return status code
859 static int fcoe_fip_tx_keepalive ( struct fcoe_port
*fcoe
) {
860 struct io_buffer
*iobuf
;
862 struct fip_header hdr
;
863 struct fip_mac_address mac_address
;
864 } __attribute__ (( packed
)) *keepalive
;
867 /* Allocate I/O buffer */
868 iobuf
= alloc_iob ( MAX_LL_HEADER_LEN
+ sizeof ( *keepalive
) );
871 iob_reserve ( iobuf
, MAX_LL_HEADER_LEN
);
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
) );
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
) );
903 /** Protocol subcode */
909 * @v descs Descriptor list
911 * @ret rc Return status code
913 int ( * rx
) ( struct fcoe_port
*fcoe
, struct fip_descriptors
*descs
,
914 unsigned int flags
);
918 static struct fip_handler fip_handlers
[] = {
919 { FIP_CODE_VLAN
, FIP_VLAN_NOTIFY
,
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
},
928 * Process incoming FIP packets
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
937 static int fcoe_fip_rx ( struct io_buffer
*iobuf
,
938 struct net_device
*netdev
,
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
;
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
);
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
) );
969 /* Parse FIP packet */
970 if ( ( rc
= fcoe_fip_parse ( fcoe
, fiphdr
, iob_len ( iobuf
),
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
) );
985 DBGC ( fcoe
, "FCoE %s received unsupported FIP code %04x.%02x\n",
986 fcoe
->netdev
->name
, ntohs ( fiphdr
->code
), fiphdr
->subcode
);
994 /******************************************************************************
998 ******************************************************************************
1002 * Handle FCoE timer expiry
1004 * @v timer FIP timer
1005 * @v over Timer expired
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
);
1013 assert ( fcoe
->flags
& FCOE_HAVE_NETWORK
);
1015 /* Increment the timeout counter */
1018 if ( vlan_can_be_trunk ( fcoe
->netdev
) &&
1019 ! ( fcoe
->flags
& FCOE_VLAN_TIMED_OUT
) ) {
1021 /* If we have already found a VLAN, send infrequent
1022 * VLAN requests, in case VLAN information changes.
1024 if ( fcoe
->flags
& FCOE_VLAN_FOUND
) {
1025 fcoe
->flags
&= ~FCOE_VLAN_FOUND
;
1027 start_timer_fixed ( &fcoe
->timer
,
1028 FCOE_VLAN_POLL_DELAY
);
1029 fcoe_fip_tx_vlan ( fcoe
);
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.
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
);
1044 /* We have timed out waiting for a VLAN; proceed to
1047 fcoe
->flags
|= FCOE_VLAN_TIMED_OUT
;
1049 DBGC ( fcoe
, "FCoE %s giving up on VLAN discovery\n",
1050 fcoe
->netdev
->name
);
1051 start_timer_nodelay ( &fcoe
->timer
);
1053 } else if ( ! ( fcoe
->flags
& FCOE_HAVE_FCF
) ) {
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.
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
);
1066 /* Attach Fibre Channel port */
1067 if ( ( rc
= fc_port_open ( &fcoe
->transport
, &fcoe
->node_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 */
1075 stop_timer ( &fcoe
->timer
);
1077 /* Either we have found a FIP-capable forwarder, or we
1078 * have timed out and will fall back to pre-FIP mode.
1080 fcoe
->flags
|= FCOE_HAVE_FCF
;
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
) );
1086 /* Start sending keepalives if applicable */
1087 if ( fcoe
->keepalive
)
1088 start_timer_nodelay ( &fcoe
->timer
);
1090 /* Send notification of window change */
1091 xfer_window_changed ( &fcoe
->transport
);
1095 /* Send keepalive */
1096 start_timer_fixed ( &fcoe
->timer
,
1097 ( ( fcoe
->keepalive
* TICKS_PER_SEC
) / 1000 ) );
1098 fcoe_fip_tx_keepalive ( fcoe
);
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
);
1112 * @v netdev Network device
1113 * @ret rc Return status code
1115 static int fcoe_probe ( struct net_device
*netdev
) {
1116 struct ll_protocol
*ll_protocol
= netdev
->ll_protocol
;
1117 struct fcoe_port
*fcoe
;
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
);
1125 goto err_non_ethernet
;
1128 /* Allocate and initialise structure */
1129 fcoe
= zalloc ( sizeof ( *fcoe
) );
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
);
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
) );
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
) );
1151 /* Transfer reference to port list */
1152 list_add ( &fcoe
->list
, &fcoe_ports
);
1155 netdev_put ( fcoe
->netdev
);
1162 * Handle FCoE port device or link state change
1164 * @v netdev Network device
1166 static void fcoe_notify ( struct net_device
*netdev
) {
1167 struct fcoe_port
*fcoe
;
1170 if ( ( fcoe
= fcoe_demux ( netdev
) ) == NULL
) {
1171 DBG ( "FCoE notification for net device %s missing FCoE "
1172 "port\n", netdev
->name
);
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
);
1187 * @v netdev Network device
1189 static void fcoe_remove ( struct net_device
*netdev
) {
1190 struct fcoe_port
*fcoe
;
1193 if ( ( fcoe
= fcoe_demux ( netdev
) ) == NULL
) {
1194 DBG ( "FCoE removal of net device %s missing FCoE port\n",
1199 /* Close FCoE device */
1200 fcoe_close ( fcoe
, 0 );
1204 struct net_driver fcoe_driver __net_driver
= {
1206 .probe
= fcoe_probe
,
1207 .notify
= fcoe_notify
,
1208 .remove
= fcoe_remove
,
1211 /** FCoE protocol */
1212 struct net_protocol fcoe_protocol __net_protocol
= {
1214 .net_proto
= htons ( ETH_P_FCOE
),
1219 struct net_protocol fip_protocol __net_protocol
= {
1221 .net_proto
= htons ( ETH_P_FIP
),
1225 /** Human-readable message for CRC errors
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.
1231 struct errortab fcoe_errors
[] __errortab
= {
1232 __einfo_errortab ( EINFO_EINVAL_CRC
),