|
|
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.