|  | @@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 | 
		
	
		
			
			| 29 | 29 |  #include <ipxe/xfer.h>
 | 
		
	
		
			
			| 30 | 30 |  #include <ipxe/netdevice.h>
 | 
		
	
		
			
			| 31 | 31 |  #include <ipxe/ethernet.h>
 | 
		
	
		
			
			|  | 32 | +#include <ipxe/vlan.h>
 | 
		
	
		
			
			| 32 | 33 |  #include <ipxe/features.h>
 | 
		
	
		
			
			| 33 | 34 |  #include <ipxe/errortab.h>
 | 
		
	
		
			
			| 34 | 35 |  #include <ipxe/device.h>
 | 
		
	
	
		
			
			|  | @@ -103,6 +104,10 @@ enum fcoe_flags {
 | 
		
	
		
			
			| 103 | 104 |  	FCOE_HAVE_FIP_FCF = 0x0004,
 | 
		
	
		
			
			| 104 | 105 |  	/** FCoE forwarder supports server-provided MAC addresses */
 | 
		
	
		
			
			| 105 | 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,
 | 
		
	
		
			
			| 106 | 111 |  };
 | 
		
	
		
			
			| 107 | 112 |  
 | 
		
	
		
			
			| 108 | 113 |  struct net_protocol fcoe_protocol __net_protocol;
 | 
		
	
	
		
			
			|  | @@ -124,6 +129,15 @@ static uint8_t all_fcf_macs[ETH_ALEN] =
 | 
		
	
		
			
			| 124 | 129 |  static uint8_t default_fcf_mac[ETH_ALEN] =
 | 
		
	
		
			
			| 125 | 130 |  	{ 0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe };
 | 
		
	
		
			
			| 126 | 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 | +
 | 
		
	
		
			
			| 127 | 141 |  /** Maximum number of FIP solicitations before giving up on FIP */
 | 
		
	
		
			
			| 128 | 142 |  #define FCOE_MAX_FIP_SOLICITATIONS 2
 | 
		
	
		
			
			| 129 | 143 |  
 | 
		
	
	
		
			
			|  | @@ -182,8 +196,9 @@ static void fcoe_reset ( struct fcoe_port *fcoe ) {
 | 
		
	
		
			
			| 182 | 196 |  	     netdev_link_ok ( fcoe->netdev ) ) {
 | 
		
	
		
			
			| 183 | 197 |  		fcoe->flags |= FCOE_HAVE_NETWORK;
 | 
		
	
		
			
			| 184 | 198 |  		start_timer_nodelay ( &fcoe->timer );
 | 
		
	
		
			
			| 185 |  | -		DBGC ( fcoe, "FCoE %s starting FIP solicitation\n",
 | 
		
	
		
			
			| 186 |  | -		       fcoe->netdev->name );
 | 
		
	
		
			
			|  | 199 | +		DBGC ( fcoe, "FCoE %s starting %s\n", fcoe->netdev->name,
 | 
		
	
		
			
			|  | 200 | +		       ( vlan_can_be_trunk ( fcoe->netdev ) ?
 | 
		
	
		
			
			|  | 201 | +			 "VLAN discovery" : "FIP solicitation" ) );
 | 
		
	
		
			
			| 187 | 202 |  	}
 | 
		
	
		
			
			| 188 | 203 |  
 | 
		
	
		
			
			| 189 | 204 |  	/* Send notification of window change */
 | 
		
	
	
		
			
			|  | @@ -533,6 +548,100 @@ static int fcoe_fip_parse ( struct fcoe_port *fcoe, struct fip_header *fiphdr,
 | 
		
	
		
			
			| 533 | 548 |  	return 0;
 | 
		
	
		
			
			| 534 | 549 |  }
 | 
		
	
		
			
			| 535 | 550 |  
 | 
		
	
		
			
			|  | 551 | +/**
 | 
		
	
		
			
			|  | 552 | + * Send FIP VLAN request
 | 
		
	
		
			
			|  | 553 | + *
 | 
		
	
		
			
			|  | 554 | + * @v fcoe		FCoE port
 | 
		
	
		
			
			|  | 555 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 556 | + */
 | 
		
	
		
			
			|  | 557 | +static int fcoe_fip_tx_vlan ( struct fcoe_port *fcoe ) {
 | 
		
	
		
			
			|  | 558 | +	struct io_buffer *iobuf;
 | 
		
	
		
			
			|  | 559 | +	struct {
 | 
		
	
		
			
			|  | 560 | +		struct fip_header hdr;
 | 
		
	
		
			
			|  | 561 | +		struct fip_mac_address mac_address;
 | 
		
	
		
			
			|  | 562 | +	} __attribute__ (( packed )) *request;
 | 
		
	
		
			
			|  | 563 | +	int rc;
 | 
		
	
		
			
			|  | 564 | +
 | 
		
	
		
			
			|  | 565 | +	/* Allocate I/O buffer */
 | 
		
	
		
			
			|  | 566 | +	iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *request ) );
 | 
		
	
		
			
			|  | 567 | +	if ( ! iobuf )
 | 
		
	
		
			
			|  | 568 | +		return -ENOMEM;
 | 
		
	
		
			
			|  | 569 | +	iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
 | 
		
	
		
			
			|  | 570 | +
 | 
		
	
		
			
			|  | 571 | +	/* Construct VLAN request */
 | 
		
	
		
			
			|  | 572 | +	request = iob_put ( iobuf, sizeof ( *request ) );
 | 
		
	
		
			
			|  | 573 | +	memset ( request, 0, sizeof ( *request ) );
 | 
		
	
		
			
			|  | 574 | +	request->hdr.version = FIP_VERSION;
 | 
		
	
		
			
			|  | 575 | +	request->hdr.code = htons ( FIP_CODE_VLAN );
 | 
		
	
		
			
			|  | 576 | +	request->hdr.subcode = FIP_VLAN_REQUEST;
 | 
		
	
		
			
			|  | 577 | +	request->hdr.len = htons ( ( sizeof ( *request ) -
 | 
		
	
		
			
			|  | 578 | +				     sizeof ( request->hdr ) ) / 4 );
 | 
		
	
		
			
			|  | 579 | +	request->mac_address.type = FIP_MAC_ADDRESS;
 | 
		
	
		
			
			|  | 580 | +	request->mac_address.len =
 | 
		
	
		
			
			|  | 581 | +		( sizeof ( request->mac_address ) / 4 );
 | 
		
	
		
			
			|  | 582 | +	memcpy ( request->mac_address.mac, fcoe->netdev->ll_addr,
 | 
		
	
		
			
			|  | 583 | +		 sizeof ( request->mac_address.mac ) );
 | 
		
	
		
			
			|  | 584 | +
 | 
		
	
		
			
			|  | 585 | +	/* Send VLAN request */
 | 
		
	
		
			
			|  | 586 | +	if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev,
 | 
		
	
		
			
			|  | 587 | +			     &fip_protocol, all_fcf_macs,
 | 
		
	
		
			
			|  | 588 | +			     fcoe->netdev->ll_addr ) ) != 0 ) {
 | 
		
	
		
			
			|  | 589 | +		DBGC ( fcoe, "FCoE %s could not send VLAN request: "
 | 
		
	
		
			
			|  | 590 | +		       "%s\n", fcoe->netdev->name, strerror ( rc ) );
 | 
		
	
		
			
			|  | 591 | +		return rc;
 | 
		
	
		
			
			|  | 592 | +	}
 | 
		
	
		
			
			|  | 593 | +
 | 
		
	
		
			
			|  | 594 | +	return 0;
 | 
		
	
		
			
			|  | 595 | +}
 | 
		
	
		
			
			|  | 596 | +
 | 
		
	
		
			
			|  | 597 | +/**
 | 
		
	
		
			
			|  | 598 | + * Handle received FIP VLAN notification
 | 
		
	
		
			
			|  | 599 | + *
 | 
		
	
		
			
			|  | 600 | + * @v fcoe		FCoE port
 | 
		
	
		
			
			|  | 601 | + * @v descs		Descriptor list
 | 
		
	
		
			
			|  | 602 | + * @v flags		Flags
 | 
		
	
		
			
			|  | 603 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 604 | + */
 | 
		
	
		
			
			|  | 605 | +static int fcoe_fip_rx_vlan ( struct fcoe_port *fcoe,
 | 
		
	
		
			
			|  | 606 | +			      struct fip_descriptors *descs,
 | 
		
	
		
			
			|  | 607 | +			      unsigned int flags __unused ) {
 | 
		
	
		
			
			|  | 608 | +	struct fip_mac_address *mac_address = fip_mac_address ( descs );
 | 
		
	
		
			
			|  | 609 | +	struct fip_vlan *vlan = fip_vlan ( descs );
 | 
		
	
		
			
			|  | 610 | +	unsigned int tag;
 | 
		
	
		
			
			|  | 611 | +	int rc;
 | 
		
	
		
			
			|  | 612 | +
 | 
		
	
		
			
			|  | 613 | +	/* Sanity checks */
 | 
		
	
		
			
			|  | 614 | +	if ( ! mac_address ) {
 | 
		
	
		
			
			|  | 615 | +		DBGC ( fcoe, "FCoE %s received VLAN notification missing MAC "
 | 
		
	
		
			
			|  | 616 | +		       "address\n", fcoe->netdev->name );
 | 
		
	
		
			
			|  | 617 | +		return -EINVAL;
 | 
		
	
		
			
			|  | 618 | +	}
 | 
		
	
		
			
			|  | 619 | +	if ( ! vlan ) {
 | 
		
	
		
			
			|  | 620 | +		DBGC ( fcoe, "FCoE %s received VLAN notification missing VLAN "
 | 
		
	
		
			
			|  | 621 | +		       "tag\n", fcoe->netdev->name );
 | 
		
	
		
			
			|  | 622 | +		return -EINVAL;
 | 
		
	
		
			
			|  | 623 | +	}
 | 
		
	
		
			
			|  | 624 | +
 | 
		
	
		
			
			|  | 625 | +	/* Create VLAN */
 | 
		
	
		
			
			|  | 626 | +	tag = ntohs ( vlan->vlan );
 | 
		
	
		
			
			|  | 627 | +	DBGC ( fcoe, "FCoE %s creating VLAN %d for FCF %s\n",
 | 
		
	
		
			
			|  | 628 | +	       fcoe->netdev->name, tag, eth_ntoa ( mac_address->mac ) );
 | 
		
	
		
			
			|  | 629 | +	if ( ( rc = vlan_create ( fcoe->netdev, tag,
 | 
		
	
		
			
			|  | 630 | +				  FCOE_VLAN_PRIORITY ) ) != 0 ) {
 | 
		
	
		
			
			|  | 631 | +		DBGC ( fcoe, "FCoE %s could not create VLAN %d: %s\n",
 | 
		
	
		
			
			|  | 632 | +		       fcoe->netdev->name, tag, strerror ( rc ) );
 | 
		
	
		
			
			|  | 633 | +		return rc;
 | 
		
	
		
			
			|  | 634 | +	}
 | 
		
	
		
			
			|  | 635 | +
 | 
		
	
		
			
			|  | 636 | +	/* Record that a VLAN was found.  This FCoE port will play no
 | 
		
	
		
			
			|  | 637 | +	 * further active role; the real FCoE traffic will use the
 | 
		
	
		
			
			|  | 638 | +	 * port automatically created for the new VLAN device.
 | 
		
	
		
			
			|  | 639 | +	 */
 | 
		
	
		
			
			|  | 640 | +	fcoe->flags |= FCOE_VLAN_FOUND;
 | 
		
	
		
			
			|  | 641 | +
 | 
		
	
		
			
			|  | 642 | +	return 0;
 | 
		
	
		
			
			|  | 643 | +}
 | 
		
	
		
			
			|  | 644 | +
 | 
		
	
		
			
			| 536 | 645 |  /**
 | 
		
	
		
			
			| 537 | 646 |   * Send FIP discovery solicitation
 | 
		
	
		
			
			| 538 | 647 |   *
 | 
		
	
	
		
			
			|  | @@ -797,6 +906,8 @@ struct fip_handler {
 | 
		
	
		
			
			| 797 | 906 |  
 | 
		
	
		
			
			| 798 | 907 |  /** FIP handlers */
 | 
		
	
		
			
			| 799 | 908 |  static struct fip_handler fip_handlers[] = {
 | 
		
	
		
			
			|  | 909 | +	{ FIP_CODE_VLAN, FIP_VLAN_NOTIFY,
 | 
		
	
		
			
			|  | 910 | +	  fcoe_fip_rx_vlan },
 | 
		
	
		
			
			| 800 | 911 |  	{ FIP_CODE_DISCOVERY, FIP_DISCOVERY_ADVERTISE,
 | 
		
	
		
			
			| 801 | 912 |  	  fcoe_fip_rx_advertisement },
 | 
		
	
		
			
			| 802 | 913 |  	{ FIP_CODE_ELS, FIP_ELS_RESPONSE,
 | 
		
	
	
		
			
			|  | @@ -891,7 +1002,42 @@ static void fcoe_expired ( struct retry_timer *timer, int over __unused ) {
 | 
		
	
		
			
			| 891 | 1002 |  	/* Increment the timeout counter */
 | 
		
	
		
			
			| 892 | 1003 |  	fcoe->timeouts++;
 | 
		
	
		
			
			| 893 | 1004 |  
 | 
		
	
		
			
			| 894 |  | -	if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) {
 | 
		
	
		
			
			|  | 1005 | +	if ( vlan_can_be_trunk ( fcoe->netdev ) &
 | 
		
	
		
			
			|  | 1006 | +	     ! ( fcoe->flags & FCOE_VLAN_TIMED_OUT ) ) {
 | 
		
	
		
			
			|  | 1007 | +
 | 
		
	
		
			
			|  | 1008 | +		/* If we have already found a VLAN, send infrequent
 | 
		
	
		
			
			|  | 1009 | +		 * VLAN requests, in case VLAN information changes.
 | 
		
	
		
			
			|  | 1010 | +		 */
 | 
		
	
		
			
			|  | 1011 | +		if ( fcoe->flags & FCOE_VLAN_FOUND ) {
 | 
		
	
		
			
			|  | 1012 | +			fcoe->flags &= ~FCOE_VLAN_FOUND;
 | 
		
	
		
			
			|  | 1013 | +			fcoe->timeouts = 0;
 | 
		
	
		
			
			|  | 1014 | +			start_timer_fixed ( &fcoe->timer,
 | 
		
	
		
			
			|  | 1015 | +					    FCOE_VLAN_POLL_DELAY );
 | 
		
	
		
			
			|  | 1016 | +			fcoe_fip_tx_vlan ( fcoe );
 | 
		
	
		
			
			|  | 1017 | +			return;
 | 
		
	
		
			
			|  | 1018 | +		}
 | 
		
	
		
			
			|  | 1019 | +
 | 
		
	
		
			
			|  | 1020 | +		/* If we have not yet found a VLAN, and we have not
 | 
		
	
		
			
			|  | 1021 | +		 * yet timed out and given up on finding one, then
 | 
		
	
		
			
			|  | 1022 | +		 * send a VLAN request and wait.
 | 
		
	
		
			
			|  | 1023 | +		 */
 | 
		
	
		
			
			|  | 1024 | +		if ( fcoe->timeouts <= FCOE_MAX_VLAN_REQUESTS ) {
 | 
		
	
		
			
			|  | 1025 | +			start_timer_fixed ( &fcoe->timer,
 | 
		
	
		
			
			|  | 1026 | +					    FCOE_VLAN_RETRY_DELAY );
 | 
		
	
		
			
			|  | 1027 | +			fcoe_fip_tx_vlan ( fcoe );
 | 
		
	
		
			
			|  | 1028 | +			return;
 | 
		
	
		
			
			|  | 1029 | +		}
 | 
		
	
		
			
			|  | 1030 | +
 | 
		
	
		
			
			|  | 1031 | +		/* We have timed out waiting for a VLAN; proceed to
 | 
		
	
		
			
			|  | 1032 | +		 * FIP discovery.
 | 
		
	
		
			
			|  | 1033 | +		 */
 | 
		
	
		
			
			|  | 1034 | +		fcoe->flags |= FCOE_VLAN_TIMED_OUT;
 | 
		
	
		
			
			|  | 1035 | +		fcoe->timeouts = 0;
 | 
		
	
		
			
			|  | 1036 | +		DBGC ( fcoe, "FCoE %s giving up on VLAN discovery\n",
 | 
		
	
		
			
			|  | 1037 | +		       fcoe->netdev->name );
 | 
		
	
		
			
			|  | 1038 | +		start_timer_nodelay ( &fcoe->timer );
 | 
		
	
		
			
			|  | 1039 | +
 | 
		
	
		
			
			|  | 1040 | +	} else if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) {
 | 
		
	
		
			
			| 895 | 1041 |  
 | 
		
	
		
			
			| 896 | 1042 |  		/* If we have not yet found a FIP-capable forwarder,
 | 
		
	
		
			
			| 897 | 1043 |  		 * and we have not yet timed out and given up on
 |