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