Annotation of qemu/roms/ipxe/src/net/fcoe.c, revision 1.1.1.1

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: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.