Annotation of qemu/roms/ipxe/src/net/fc.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 <string.h>
                     24: #include <stdio.h>
                     25: #include <errno.h>
                     26: #include <assert.h>
                     27: #include <byteswap.h>
                     28: #include <ipxe/refcnt.h>
                     29: #include <ipxe/list.h>
                     30: #include <ipxe/tables.h>
                     31: #include <ipxe/timer.h>
                     32: #include <ipxe/retry.h>
                     33: #include <ipxe/interface.h>
                     34: #include <ipxe/xfer.h>
                     35: #include <ipxe/iobuf.h>
                     36: #include <ipxe/fc.h>
                     37: #include <ipxe/fcels.h>
                     38: #include <ipxe/fcns.h>
                     39: 
                     40: /** @file
                     41:  *
                     42:  * Fibre Channel
                     43:  *
                     44:  */
                     45: 
                     46: /** List of Fibre Channel ports */
                     47: LIST_HEAD ( fc_ports );
                     48: 
                     49: /** List of Fibre Channel peers */
                     50: LIST_HEAD ( fc_peers );
                     51: 
                     52: /******************************************************************************
                     53:  *
                     54:  * Well-known addresses
                     55:  *
                     56:  ******************************************************************************
                     57:  */
                     58: 
                     59: /** Unassigned port ID */
                     60: struct fc_port_id fc_empty_port_id = { .bytes = { 0x00, 0x00, 0x00 } };
                     61: 
                     62: /** F_Port contoller port ID */
                     63: struct fc_port_id fc_f_port_id = { .bytes = { 0xff, 0xff, 0xfe } };
                     64: 
                     65: /** Generic services port ID */
                     66: struct fc_port_id fc_gs_port_id = { .bytes = { 0xff, 0xff, 0xfc } };
                     67: 
                     68: /** Point-to-point low port ID */
                     69: struct fc_port_id fc_ptp_low_port_id = { .bytes = { 0x01, 0x01, 0x01 } };
                     70: 
                     71: /** Point-to-point high port ID */
                     72: struct fc_port_id fc_ptp_high_port_id = { .bytes = { 0x01, 0x01, 0x02 } };
                     73: 
                     74: /******************************************************************************
                     75:  *
                     76:  * Utility functions
                     77:  *
                     78:  ******************************************************************************
                     79:  */
                     80: 
                     81: /**
                     82:  * Format Fibre Channel port ID
                     83:  *
                     84:  * @v id               Fibre Channel port ID
                     85:  * @ret id_text                Port ID text
                     86:  */
                     87: const char * fc_id_ntoa ( const struct fc_port_id *id ) {
                     88:        static char id_text[ FC_PORT_ID_STRLEN + 1 /* NUL */ ];
                     89: 
                     90:        snprintf ( id_text, sizeof ( id_text ), "%02x.%02x.%02x",
                     91:                   id->bytes[0], id->bytes[1], id->bytes[2] );
                     92:        return id_text;
                     93: }
                     94: 
                     95: /**
                     96:  * Parse Fibre Channel port ID
                     97:  *
                     98:  * @v id_text          Port ID text
                     99:  * @ret id             Fibre Channel port ID
                    100:  * @ret rc             Return status code
                    101:  */
                    102: int fc_id_aton ( const char *id_text, struct fc_port_id *id ) {
                    103:        char *ptr = ( ( char * ) id_text );
                    104:        unsigned int i = 0;
                    105: 
                    106:        while ( 1 ) {
                    107:                id->bytes[i++] = strtoul ( ptr, &ptr, 16 );
                    108:                if ( i == sizeof ( id->bytes ) )
                    109:                        return ( ( *ptr == '\0' ) ? 0 : -EINVAL );
                    110:                if ( *ptr != '.' )
                    111:                        return -EINVAL;
                    112:                ptr++;
                    113:        }
                    114: }
                    115: 
                    116: /**
                    117:  * Format Fibre Channel WWN
                    118:  *
                    119:  * @v wwn              Fibre Channel WWN
                    120:  * @ret wwn_text       WWN text
                    121:  */
                    122: const char * fc_ntoa ( const struct fc_name *wwn ) {
                    123:        static char wwn_text[ FC_NAME_STRLEN + 1 /* NUL */ ];
                    124: 
                    125:        snprintf ( wwn_text, sizeof ( wwn_text ),
                    126:                   "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
                    127:                   wwn->bytes[0], wwn->bytes[1], wwn->bytes[2], wwn->bytes[3],
                    128:                   wwn->bytes[4], wwn->bytes[5], wwn->bytes[6], wwn->bytes[7] );
                    129:        return wwn_text;
                    130: }
                    131: 
                    132: /**
                    133:  * Parse Fibre Channel WWN
                    134:  *
                    135:  * @v wwn_text         WWN text
                    136:  * @ret wwn            Fibre Channel WWN
                    137:  * @ret rc             Return status code
                    138:  */
                    139: int fc_aton ( const char *wwn_text, struct fc_name *wwn ) {
                    140:        char *ptr = ( ( char * ) wwn_text );
                    141:        unsigned int i = 0;
                    142: 
                    143:        while ( 1 ) {
                    144:                wwn->bytes[i++] = strtoul ( ptr, &ptr, 16 );
                    145:                if ( i == sizeof ( wwn->bytes ) )
                    146:                        return ( ( *ptr == '\0' ) ? 0 : -EINVAL );
                    147:                if ( *ptr != ':' )
                    148:                        return -EINVAL;
                    149:                ptr++;
                    150:        }
                    151: }
                    152: 
                    153: /**
                    154:  * Fill Fibre Channel socket address
                    155:  *
                    156:  * @v sa_fc            Fibre Channel socket address to fill in
                    157:  * @v id               Fibre Channel port ID
                    158:  * @ret sa             Socket address
                    159:  */
                    160: struct sockaddr * fc_fill_sockaddr ( struct sockaddr_fc *sa_fc,
                    161:                                     struct fc_port_id *id ) {
                    162:        union {
                    163:                struct sockaddr sa;
                    164:                struct sockaddr_fc fc;
                    165:        } *u = container_of ( sa_fc, typeof ( *u ), fc );
                    166: 
                    167:        memset ( sa_fc, 0, sizeof ( *sa_fc ) );
                    168:        sa_fc->sfc_family = AF_FC;
                    169:        memcpy ( &sa_fc->sfc_port_id, id, sizeof ( sa_fc->sfc_port_id ) );
                    170:        return &u->sa;
                    171: }
                    172: 
                    173: /******************************************************************************
                    174:  *
                    175:  * Fibre Channel link state
                    176:  *
                    177:  ******************************************************************************
                    178:  */
                    179: 
                    180: /** Default link status code */
                    181: #define EUNKNOWN_LINK_STATUS __einfo_error ( EINFO_EUNKNOWN_LINK_STATUS )
                    182: #define EINFO_EUNKNOWN_LINK_STATUS \
                    183:        __einfo_uniqify ( EINFO_EINPROGRESS, 0x01, "Unknown" )
                    184: 
                    185: /**
                    186:  * Mark Fibre Channel link as up
                    187:  *
                    188:  * @v link             Fibre Channel link state monitor
                    189:  */
                    190: static void fc_link_up ( struct fc_link_state *link ) {
                    191: 
                    192:        /* Stop retry timer */
                    193:        stop_timer ( &link->timer );
                    194: 
                    195:        /* Record link state */
                    196:        link->rc = 0;
                    197: }
                    198: 
                    199: /**
                    200:  * Mark Fibre Channel link as down
                    201:  *
                    202:  * @v link             Fibre Channel link state monitor
                    203:  * @v rc               Link state
                    204:  */
                    205: static void fc_link_err ( struct fc_link_state *link, int rc ) {
                    206: 
                    207:        /* Record link state */
                    208:        if ( rc == 0 )
                    209:                rc = -EUNKNOWN_LINK_STATUS;
                    210:        link->rc = rc;
                    211: 
                    212:        /* Schedule another link examination */
                    213:        start_timer_fixed ( &link->timer, FC_LINK_RETRY_DELAY );
                    214: }
                    215: 
                    216: /**
                    217:  * Examine Fibre Channel link state
                    218:  *
                    219:  * @v link             Fibre Channel link state monitor
                    220:  */
                    221: static void fc_link_examine ( struct fc_link_state *link ) {
                    222: 
                    223:        link->examine ( link );
                    224: }
                    225: 
                    226: /**
                    227:  * Handle Fibre Channel link retry timer expiry
                    228:  */
                    229: static void fc_link_expired ( struct retry_timer *timer, int over __unused ) {
                    230:        struct fc_link_state *link =
                    231:                container_of ( timer, struct fc_link_state, timer );
                    232: 
                    233:        /* Schedule another link examination */
                    234:        start_timer_fixed ( &link->timer, FC_LINK_RETRY_DELAY );
                    235: 
                    236:        /* Examine link */
                    237:        fc_link_examine ( link );
                    238: }
                    239: 
                    240: /**
                    241:  * Initialise Fibre Channel link state monitor
                    242:  *
                    243:  * @v link             Fibre Channel link state monitor
                    244:  * @v examine          Examine link state method
                    245:  * @v refcnt           Reference counter
                    246:  */
                    247: static void fc_link_init ( struct fc_link_state *link,
                    248:                           void ( * examine ) ( struct fc_link_state *link ),
                    249:                           struct refcnt *refcnt ) {
                    250: 
                    251:        link->rc = -EUNKNOWN_LINK_STATUS;
                    252:        timer_init ( &link->timer, fc_link_expired, refcnt );
                    253:        link->examine = examine;
                    254: }
                    255: 
                    256: /**
                    257:  * Start monitoring Fibre Channel link state
                    258:  *
                    259:  * @v link             Fibre Channel link state monitor
                    260:  */
                    261: static void fc_link_start ( struct fc_link_state *link ) {
                    262:        start_timer_nodelay ( &link->timer );
                    263: }
                    264: 
                    265: /**
                    266:  * Stop monitoring Fibre Channel link state
                    267:  *
                    268:  * @v link             Fibre Channel link state monitor
                    269:  */
                    270: static void fc_link_stop ( struct fc_link_state *link ) {
                    271:        stop_timer ( &link->timer );
                    272: }
                    273: 
                    274: /******************************************************************************
                    275:  *
                    276:  * Fibre Channel exchanges
                    277:  *
                    278:  ******************************************************************************
                    279:  */
                    280: 
                    281: /** A Fibre Channel exchange */
                    282: struct fc_exchange {
                    283:        /** Reference count */
                    284:        struct refcnt refcnt;
                    285:        /** Fibre Channel port */
                    286:        struct fc_port *port;
                    287:        /** List of active exchanges within this port */
                    288:        struct list_head list;
                    289: 
                    290:        /** Peer port ID */
                    291:        struct fc_port_id peer_port_id;
                    292:        /** Data structure type */
                    293:        unsigned int type;
                    294:        /** Flags */
                    295:        unsigned int flags;
                    296:        /** Local exchange ID */
                    297:        uint16_t xchg_id;
                    298:        /** Peer exchange ID */
                    299:        uint16_t peer_xchg_id;
                    300:        /** Active sequence ID */
                    301:        uint8_t seq_id;
                    302:        /** Active sequence count */
                    303:        uint16_t seq_cnt;
                    304: 
                    305:        /** Timeout timer */
                    306:        struct retry_timer timer;
                    307: 
                    308:        /** Upper-layer protocol interface */
                    309:        struct interface ulp;
                    310: };
                    311: 
                    312: /** Fibre Channel exchange flags */
                    313: enum fc_exchange_flags {
                    314:        /** We are the exchange originator */
                    315:        FC_XCHG_ORIGINATOR = 0x0001,
                    316:        /** We have the sequence initiative */
                    317:        FC_XCHG_SEQ_INITIATIVE = 0x0002,
                    318:        /** This is the first sequence of the exchange */
                    319:        FC_XCHG_SEQ_FIRST = 0x0004,
                    320: };
                    321: 
                    322: /** Fibre Channel timeout */
                    323: #define FC_TIMEOUT ( 1 * TICKS_PER_SEC )
                    324: 
                    325: /**
                    326:  * Create local Fibre Channel exchange identifier
                    327:  *
                    328:  * @ret xchg_id                Local exchange ID
                    329:  */
                    330: static unsigned int fc_new_xchg_id ( void ) {
                    331:        static uint16_t next_id = 0x0000;
                    332: 
                    333:        /* We must avoid using FC_RX_ID_UNKNOWN (0xffff) */
                    334:        next_id += 2;
                    335:        return next_id;
                    336: }
                    337: 
                    338: /**
                    339:  * Create local Fibre Channel sequence identifier
                    340:  *
                    341:  * @ret seq_id         Local sequence identifier
                    342:  */
                    343: static unsigned int fc_new_seq_id ( void ) {
                    344:        static uint8_t seq_id = 0x00;
                    345: 
                    346:        return (++seq_id);
                    347: }
                    348: 
                    349: /**
                    350:  * Free Fibre Channel exchange
                    351:  *
                    352:  * @v refcnt           Reference count
                    353:  */
                    354: static void fc_xchg_free ( struct refcnt *refcnt ) {
                    355:        struct fc_exchange *xchg =
                    356:                container_of ( refcnt, struct fc_exchange, refcnt );
                    357: 
                    358:        assert ( ! timer_running ( &xchg->timer ) );
                    359:        assert ( list_empty ( &xchg->list ) );
                    360: 
                    361:        fc_port_put ( xchg->port );
                    362:        free ( xchg );
                    363: }
                    364: 
                    365: /**
                    366:  * Close Fibre Channel exchange
                    367:  *
                    368:  * @v xchg             Fibre Channel exchange
                    369:  * @v rc               Reason for close
                    370:  */
                    371: static void fc_xchg_close ( struct fc_exchange *xchg, int rc ) {
                    372:        struct fc_port *port = xchg->port;
                    373: 
                    374:        if ( rc != 0 ) {
                    375:                DBGC2 ( port, "FCXCHG %s/%04x closed: %s\n",
                    376:                        port->name, xchg->xchg_id, strerror ( rc ) );
                    377:        }
                    378: 
                    379:        /* Stop timer */
                    380:        stop_timer ( &xchg->timer );
                    381: 
                    382:        /* If list still holds a reference, remove from list of open
                    383:         * exchanges and drop list's reference.
                    384:         */
                    385:        if ( ! list_empty ( &xchg->list ) ) {
                    386:                list_del ( &xchg->list );
                    387:                INIT_LIST_HEAD ( &xchg->list );
                    388:                ref_put ( &xchg->refcnt );
                    389:        }
                    390: 
                    391:        /* Shutdown interfaces */
                    392:        intf_shutdown ( &xchg->ulp, rc );
                    393: }
                    394: 
                    395: /**
                    396:  * Handle exchange timeout
                    397:  *
                    398:  * @v timer            Timeout timer
                    399:  * @v over             Failure indicator
                    400:  */
                    401: static void fc_xchg_expired ( struct retry_timer *timer, int over __unused ) {
                    402:        struct fc_exchange *xchg =
                    403:                container_of ( timer, struct fc_exchange, timer );
                    404:        struct fc_port *port = xchg->port;
                    405: 
                    406:        DBGC ( port, "FCXCHG %s/%04x timed out\n", port->name, xchg->xchg_id );
                    407: 
                    408:        /* Terminate the exchange */
                    409:        fc_xchg_close ( xchg, -ETIMEDOUT );
                    410: }
                    411: 
                    412: /**
                    413:  * Check Fibre Channel exchange window
                    414:  *
                    415:  * @v xchg             Fibre Channel exchange
                    416:  * @ret len            Length opf window
                    417:  */
                    418: static size_t fc_xchg_window ( struct fc_exchange *xchg __unused ) {
                    419: 
                    420:        /* We don't currently store the path MTU */
                    421:        return FC_LOGIN_DEFAULT_MTU;
                    422: }
                    423: 
                    424: /**
                    425:  * Allocate Fibre Channel I/O buffer
                    426:  *
                    427:  * @v xchg             Fibre Channel exchange
                    428:  * @v len              Payload length
                    429:  * @ret iobuf          I/O buffer, or NULL
                    430:  */
                    431: static struct io_buffer * fc_xchg_alloc_iob ( struct fc_exchange *xchg,
                    432:                                              size_t len ) {
                    433:        struct fc_port *port = xchg->port;
                    434:        struct io_buffer *iobuf;
                    435: 
                    436:        iobuf = xfer_alloc_iob ( &port->transport,
                    437:                                 ( sizeof ( struct fc_frame_header ) + len ) );
                    438:        if ( iobuf ) {
                    439:                iob_reserve ( iobuf, sizeof ( struct fc_frame_header ) );
                    440:        }
                    441:        return iobuf;
                    442: }
                    443: 
                    444: /**
                    445:  * Transmit data as part of a Fibre Channel exchange
                    446:  *
                    447:  * @v xchg             Fibre Channel exchange
                    448:  * @v iobuf            I/O buffer
                    449:  * @v meta             Data transfer metadata
                    450:  * @ret rc             Return status code
                    451:  */
                    452: static int fc_xchg_tx ( struct fc_exchange *xchg, struct io_buffer *iobuf,
                    453:                        struct xfer_metadata *meta ) {
                    454:        struct fc_port *port = xchg->port;
                    455:        struct sockaddr_fc *dest = ( ( struct sockaddr_fc * ) meta->dest );
                    456:        struct fc_frame_header *fchdr;
                    457:        unsigned int r_ctl;
                    458:        unsigned int f_ctl_es;
                    459:        int rc;
                    460: 
                    461:        /* Sanity checks */
                    462:        if ( ! ( xchg->flags & FC_XCHG_SEQ_INITIATIVE ) ) {
                    463:                DBGC ( port, "FCXCHG %s/%04x cannot transmit while not "
                    464:                       "holding sequence initiative\n",
                    465:                       port->name, xchg->xchg_id );
                    466:                rc = -EBUSY;
                    467:                goto done;
                    468:        }
                    469: 
                    470:        /* Calculate routing control */
                    471:        switch ( xchg->type ) {
                    472:        case FC_TYPE_ELS:
                    473:                r_ctl = FC_R_CTL_ELS;
                    474:                if ( meta->flags & XFER_FL_RESPONSE ) {
                    475:                        r_ctl |= FC_R_CTL_SOL_CTRL;
                    476:                } else {
                    477:                        r_ctl |= FC_R_CTL_UNSOL_CTRL;
                    478:                }
                    479:                break;
                    480:        case FC_TYPE_CT:
                    481:                r_ctl = FC_R_CTL_DATA;
                    482:                if ( meta->flags & XFER_FL_RESPONSE ) {
                    483:                        r_ctl |= FC_R_CTL_SOL_CTRL;
                    484:                } else {
                    485:                        r_ctl |= FC_R_CTL_UNSOL_CTRL;
                    486:                }
                    487:                break;
                    488:        default:
                    489:                r_ctl = FC_R_CTL_DATA;
                    490:                switch ( meta->flags &
                    491:                         ( XFER_FL_CMD_STAT | XFER_FL_RESPONSE ) ) {
                    492:                case ( XFER_FL_CMD_STAT | XFER_FL_RESPONSE ):
                    493:                        r_ctl |= FC_R_CTL_CMD_STAT;
                    494:                        break;
                    495:                case ( XFER_FL_CMD_STAT ):
                    496:                        r_ctl |= FC_R_CTL_UNSOL_CMD;
                    497:                        break;
                    498:                case ( XFER_FL_RESPONSE ):
                    499:                        r_ctl |= FC_R_CTL_SOL_DATA;
                    500:                        break;
                    501:                default:
                    502:                        r_ctl |= FC_R_CTL_UNSOL_DATA;
                    503:                        break;
                    504:                }
                    505:                break;
                    506:        }
                    507: 
                    508:        /* Calculate exchange and sequence control */
                    509:        f_ctl_es = 0;
                    510:        if ( ! ( xchg->flags & FC_XCHG_ORIGINATOR ) )
                    511:                f_ctl_es |= FC_F_CTL_ES_RESPONDER;
                    512:        if ( xchg->flags & FC_XCHG_SEQ_FIRST )
                    513:                f_ctl_es |= FC_F_CTL_ES_FIRST;
                    514:        if ( meta->flags & XFER_FL_OUT )
                    515:                f_ctl_es |= ( FC_F_CTL_ES_END | FC_F_CTL_ES_LAST );
                    516:        if ( meta->flags & XFER_FL_OVER )
                    517:                f_ctl_es |= ( FC_F_CTL_ES_END | FC_F_CTL_ES_TRANSFER );
                    518: 
                    519:        /* Create frame header */
                    520:        fchdr = iob_push ( iobuf, sizeof ( *fchdr ) );
                    521:        memset ( fchdr, 0, sizeof ( *fchdr ) );
                    522:        fchdr->r_ctl = r_ctl;
                    523:        memcpy ( &fchdr->d_id,
                    524:                 ( dest ? &dest->sfc_port_id : &xchg->peer_port_id ),
                    525:                 sizeof ( fchdr->d_id ) );
                    526:        memcpy ( &fchdr->s_id, &port->port_id, sizeof ( fchdr->s_id ) );
                    527:        fchdr->type = xchg->type;
                    528:        fchdr->f_ctl_es = f_ctl_es;
                    529:        fchdr->seq_id = xchg->seq_id;
                    530:        fchdr->seq_cnt = htons ( xchg->seq_cnt++ );
                    531:        fchdr->ox_id = htons ( ( xchg->flags & FC_XCHG_ORIGINATOR ) ?
                    532:                               xchg->xchg_id : xchg->peer_xchg_id );
                    533:        fchdr->rx_id = htons ( ( xchg->flags & FC_XCHG_ORIGINATOR ) ?
                    534:                               xchg->peer_xchg_id : xchg->xchg_id );
                    535:        if ( meta->flags & XFER_FL_ABS_OFFSET ) {
                    536:                fchdr->f_ctl_misc |= FC_F_CTL_MISC_REL_OFF;
                    537:                fchdr->parameter = htonl ( meta->offset );
                    538:        }
                    539: 
                    540:        /* Relinquish sequence initiative if applicable */
                    541:        if ( meta->flags & XFER_FL_OVER ) {
                    542:                xchg->flags &= ~( FC_XCHG_SEQ_INITIATIVE | FC_XCHG_SEQ_FIRST );
                    543:                xchg->seq_cnt = 0;
                    544:        }
                    545: 
                    546:        /* Reset timeout */
                    547:        start_timer_fixed ( &xchg->timer, FC_TIMEOUT );
                    548: 
                    549:        /* Deliver frame */
                    550:        if ( ( rc = xfer_deliver_iob ( &port->transport,
                    551:                                       iob_disown ( iobuf ) ) ) != 0 ) {
                    552:                DBGC ( port, "FCXCHG %s/%04x cannot transmit: %s\n",
                    553:                       port->name, xchg->xchg_id, strerror ( rc ) );
                    554:                goto done;
                    555:        }
                    556: 
                    557:  done:
                    558:        free_iob ( iobuf );
                    559:        return rc;
                    560: }
                    561: 
                    562: /** Mapping from Fibre Channel routing control information to xfer metadata */
                    563: static const uint8_t fc_r_ctl_info_meta_flags[ FC_R_CTL_INFO_MASK + 1 ] = {
                    564:        [FC_R_CTL_UNCAT]        = ( 0 ),
                    565:        [FC_R_CTL_SOL_DATA]     = ( XFER_FL_RESPONSE ),
                    566:        [FC_R_CTL_UNSOL_CTRL]   = ( XFER_FL_CMD_STAT ),
                    567:        [FC_R_CTL_SOL_CTRL]     = ( XFER_FL_CMD_STAT ),
                    568:        [FC_R_CTL_UNSOL_DATA]   = ( 0 ),
                    569:        [FC_R_CTL_DATA_DESC]    = ( XFER_FL_CMD_STAT ),
                    570:        [FC_R_CTL_UNSOL_CMD]    = ( XFER_FL_CMD_STAT ),
                    571:        [FC_R_CTL_CMD_STAT]     = ( XFER_FL_CMD_STAT | XFER_FL_RESPONSE ),
                    572: };
                    573: 
                    574: /**
                    575:  * Receive data as part of a Fibre Channel exchange
                    576:  *
                    577:  * @v xchg             Fibre Channel exchange
                    578:  * @v iobuf            I/O buffer
                    579:  * @v meta             Data transfer metadata
                    580:  * @ret rc             Return status code
                    581:  */
                    582: static int fc_xchg_rx ( struct fc_exchange *xchg, struct io_buffer *iobuf,
                    583:                        struct xfer_metadata *meta __unused ) {
                    584:        struct fc_port *port = xchg->port;
                    585:        struct fc_frame_header *fchdr = iobuf->data;
                    586:        struct xfer_metadata fc_meta;
                    587:        struct sockaddr_fc src;
                    588:        struct sockaddr_fc dest;
                    589:        int rc;
                    590: 
                    591:        /* Record peer exchange ID */
                    592:        xchg->peer_xchg_id =
                    593:                ntohs ( ( fchdr->f_ctl_es & FC_F_CTL_ES_RESPONDER ) ?
                    594:                        fchdr->rx_id : fchdr->ox_id );
                    595: 
                    596:        /* Sequence checks */
                    597:        if ( xchg->flags & FC_XCHG_SEQ_INITIATIVE ) {
                    598:                DBGC ( port, "FCXCHG %s/%04x received frame while holding "
                    599:                       "sequence initiative\n", port->name, xchg->xchg_id );
                    600:                rc = -EBUSY;
                    601:                goto done;
                    602:        }
                    603:        if ( ntohs ( fchdr->seq_cnt ) != xchg->seq_cnt ) {
                    604:                DBGC ( port, "FCXCHG %s/%04x received out-of-order frame %d "
                    605:                       "(expected %d)\n", port->name, xchg->xchg_id,
                    606:                       ntohs ( fchdr->seq_cnt ), xchg->seq_cnt );
                    607:                rc = -EPIPE;
                    608:                goto done;
                    609:        }
                    610:        if ( xchg->seq_cnt == 0 )
                    611:                xchg->seq_id = fchdr->seq_id;
                    612:        xchg->seq_cnt++;
                    613:        if ( fchdr->seq_id != xchg->seq_id ) {
                    614:                DBGC ( port, "FCXCHG %s/%04x received frame for incorrect "
                    615:                       "sequence %02x (expected %02x)\n", port->name,
                    616:                       xchg->xchg_id, fchdr->seq_id, xchg->seq_id );
                    617:                rc = -EPIPE;
                    618:                goto done;
                    619:        }
                    620: 
                    621:        /* Check for end of sequence and transfer of sequence initiative */
                    622:        if ( fchdr->f_ctl_es & FC_F_CTL_ES_END ) {
                    623:                xchg->seq_cnt = 0;
                    624:                if ( fchdr->f_ctl_es & FC_F_CTL_ES_TRANSFER ) {
                    625:                        xchg->flags |= FC_XCHG_SEQ_INITIATIVE;
                    626:                        xchg->seq_id = fc_new_seq_id();
                    627:                }
                    628:        }
                    629: 
                    630:        /* Construct metadata */
                    631:        memset ( &fc_meta, 0, sizeof ( fc_meta ) );
                    632:        fc_meta.flags =
                    633:                fc_r_ctl_info_meta_flags[ fchdr->r_ctl & FC_R_CTL_INFO_MASK ];
                    634:        if ( fchdr->f_ctl_es & FC_F_CTL_ES_TRANSFER ) {
                    635:                fc_meta.flags |= XFER_FL_OVER;
                    636:        }
                    637:        if ( ( fchdr->f_ctl_es & FC_F_CTL_ES_LAST ) &&
                    638:             ( fchdr->f_ctl_es & FC_F_CTL_ES_END ) ) {
                    639:                fc_meta.flags |= XFER_FL_OUT;
                    640:        }
                    641:        if ( fchdr->f_ctl_misc & FC_F_CTL_MISC_REL_OFF ) {
                    642:                fc_meta.flags |= XFER_FL_ABS_OFFSET;
                    643:                fc_meta.offset = ntohl ( fchdr->parameter );
                    644:        }
                    645:        fc_meta.src = fc_fill_sockaddr ( &src, &fchdr->s_id );
                    646:        fc_meta.dest = fc_fill_sockaddr ( &dest, &fchdr->d_id );
                    647: 
                    648:        /* Reset timeout */
                    649:        start_timer_fixed ( &xchg->timer, FC_TIMEOUT );
                    650: 
                    651:        /* Deliver via exchange's ULP interface */
                    652:        iob_pull ( iobuf, sizeof ( *fchdr ) );
                    653:        if ( ( rc = xfer_deliver ( &xchg->ulp, iob_disown ( iobuf ),
                    654:                                   &fc_meta ) ) != 0 ) {
                    655:                DBGC ( port, "FCXCHG %s/%04x cannot deliver frame: %s\n",
                    656:                       port->name, xchg->xchg_id, strerror ( rc ) );
                    657:                goto done;
                    658:        }
                    659: 
                    660:        /* Close exchange if applicable */
                    661:        if ( ( fchdr->f_ctl_es & FC_F_CTL_ES_LAST ) &&
                    662:             ( fchdr->f_ctl_es & FC_F_CTL_ES_END ) ) {
                    663:                fc_xchg_close ( xchg, 0 );
                    664:        }
                    665: 
                    666:  done:
                    667:        free_iob ( iobuf );
                    668:        return rc;
                    669: }
                    670: 
                    671: /** Fibre Channel exchange ULP interface operations */
                    672: static struct interface_operation fc_xchg_ulp_op[] = {
                    673:        INTF_OP ( xfer_deliver, struct fc_exchange *, fc_xchg_tx ),
                    674:        INTF_OP ( xfer_alloc_iob, struct fc_exchange *, fc_xchg_alloc_iob ),
                    675:        INTF_OP ( xfer_window, struct fc_exchange *, fc_xchg_window ),
                    676:        INTF_OP ( intf_close, struct fc_exchange *, fc_xchg_close ),
                    677: };
                    678: 
                    679: /** Fibre Channel exchange ULP interface descriptor */
                    680: static struct interface_descriptor fc_xchg_ulp_desc =
                    681:        INTF_DESC ( struct fc_exchange, ulp, fc_xchg_ulp_op );
                    682: 
                    683: /**
                    684:  * Create new Fibre Channel exchange
                    685:  *
                    686:  * @v port             Fibre Channel port
                    687:  * @v peer_port_id     Peer port ID
                    688:  * @ret xchg           Exchange, or NULL
                    689:  */
                    690: static struct fc_exchange * fc_xchg_create ( struct fc_port *port,
                    691:                                             struct fc_port_id *peer_port_id,
                    692:                                             unsigned int type ) {
                    693:        struct fc_exchange *xchg;
                    694: 
                    695:        /* Allocate and initialise structure */
                    696:        xchg = zalloc ( sizeof ( *xchg ) );
                    697:        if ( ! xchg )
                    698:                return NULL;
                    699:        ref_init ( &xchg->refcnt, fc_xchg_free );
                    700:        intf_init ( &xchg->ulp, &fc_xchg_ulp_desc, &xchg->refcnt );
                    701:        timer_init ( &xchg->timer, fc_xchg_expired, &xchg->refcnt );
                    702:        xchg->port = fc_port_get ( port );
                    703:        memcpy ( &xchg->peer_port_id, peer_port_id,
                    704:                 sizeof ( xchg->peer_port_id ) );
                    705:        xchg->type = type;
                    706:        xchg->xchg_id = fc_new_xchg_id();
                    707:        xchg->peer_xchg_id = FC_RX_ID_UNKNOWN;
                    708:        xchg->seq_id = fc_new_seq_id();
                    709: 
                    710:        /* Transfer reference to list of exchanges and return */
                    711:        list_add ( &xchg->list, &port->xchgs );
                    712:        return xchg;
                    713: }
                    714: 
                    715: /**
                    716:  * Originate a new Fibre Channel exchange
                    717:  *
                    718:  * @v parent           Interface to which to attach
                    719:  * @v port             Fibre Channel port
                    720:  * @v peer_port_id     Peer port ID
                    721:  * @ret xchg_id                Exchange ID, or negative error
                    722:  */
                    723: int fc_xchg_originate ( struct interface *parent, struct fc_port *port,
                    724:                        struct fc_port_id *peer_port_id, unsigned int type ) {
                    725:        struct fc_exchange *xchg;
                    726: 
                    727:        /* Allocate and initialise structure */
                    728:        xchg = fc_xchg_create ( port, peer_port_id, type );
                    729:        if ( ! xchg )
                    730:                return -ENOMEM;
                    731:        xchg->flags = ( FC_XCHG_ORIGINATOR | FC_XCHG_SEQ_INITIATIVE |
                    732:                        FC_XCHG_SEQ_FIRST );
                    733: 
                    734:        DBGC2 ( port, "FCXCHG %s/%04x originating to %s (type %02x)\n",
                    735:                port->name, xchg->xchg_id, fc_id_ntoa ( &xchg->peer_port_id ),
                    736:                xchg->type );
                    737: 
                    738:        /* Attach to parent interface and return */
                    739:        intf_plug_plug ( &xchg->ulp, parent );
                    740:        return xchg->xchg_id;
                    741: }
                    742: 
                    743: /**
                    744:  * Open a new responder Fibre Channel exchange
                    745:  *
                    746:  * @v port             Fibre Channel port
                    747:  * @v fchdr            Fibre Channel frame header
                    748:  * @ret xchg           Fibre Channel exchange, or NULL
                    749:  */
                    750: static struct fc_exchange * fc_xchg_respond ( struct fc_port *port,
                    751:                                              struct fc_frame_header *fchdr ) {
                    752:        struct fc_exchange *xchg;
                    753:        struct fc_responder *responder;
                    754:        unsigned int type = fchdr->type;
                    755:        int rc;
                    756: 
                    757:        /* Allocate and initialise structure */
                    758:        xchg = fc_xchg_create ( port, &fchdr->s_id, type );
                    759:        if ( ! xchg )
                    760:                return NULL;
                    761:        xchg->seq_id = fchdr->seq_id;
                    762: 
                    763:        DBGC2 ( port, "FCXCHG %s/%04x responding to %s xchg %04x (type "
                    764:                "%02x)\n", port->name, xchg->xchg_id,
                    765:                fc_id_ntoa ( &xchg->peer_port_id ),
                    766:                ntohs ( fchdr->ox_id ), xchg->type );
                    767: 
                    768:        /* Find a responder, if any */
                    769:        for_each_table_entry ( responder, FC_RESPONDERS ) {
                    770:                if ( responder->type == type ) {
                    771:                        if ( ( rc = responder->respond ( &xchg->ulp, port,
                    772:                                                         &fchdr->d_id,
                    773:                                                         &fchdr->s_id ) ) !=0 ){
                    774:                                DBGC ( port, "FCXCHG %s/%04x could not "
                    775:                                       "respond: %s\n", port->name,
                    776:                                       xchg->xchg_id, strerror ( rc ) );
                    777:                        }
                    778:                }
                    779:                break;
                    780:        }
                    781: 
                    782:        /* We may or may not have a ULP attached at this point, but
                    783:         * the exchange does exist.
                    784:         */
                    785:        return xchg;
                    786: }
                    787: 
                    788: /******************************************************************************
                    789:  *
                    790:  * Fibre Channel ports
                    791:  *
                    792:  ******************************************************************************
                    793:  */
                    794: 
                    795: /**
                    796:  * Close Fibre Channel port
                    797:  *
                    798:  * @v port             Fibre Channel port
                    799:  * @v rc               Reason for close
                    800:  */
                    801: static void fc_port_close ( struct fc_port *port, int rc ) {
                    802:        struct fc_exchange *xchg;
                    803:        struct fc_exchange *tmp;
                    804: 
                    805:        DBGC ( port, "FCPORT %s closed\n", port->name );
                    806: 
                    807:        /* Log out port, if necessary */
                    808:        if ( fc_link_ok ( &port->link ) )
                    809:                fc_port_logout ( port, rc );
                    810: 
                    811:        /* Stop link monitor */
                    812:        fc_link_stop ( &port->link );
                    813: 
                    814:        /* Shut down interfaces */
                    815:        intf_shutdown ( &port->transport, rc );
                    816:        intf_shutdown ( &port->flogi, rc );
                    817:        intf_shutdown ( &port->ns_plogi, rc );
                    818: 
                    819:        /* Shut down any remaining exchanges */
                    820:        list_for_each_entry_safe ( xchg, tmp, &port->xchgs, list )
                    821:                fc_xchg_close ( xchg, rc );
                    822: 
                    823:        /* Remove from list of ports */
                    824:        list_del ( &port->list );
                    825:        INIT_LIST_HEAD ( &port->list );
                    826: }
                    827: 
                    828: /**
                    829:  * Identify Fibre Channel exchange by local exchange ID
                    830:  *
                    831:  * @v port             Fibre Channel port
                    832:  * @v xchg_id          Local exchange ID
                    833:  * @ret xchg           Fibre Channel exchange, or NULL
                    834:  */
                    835: static struct fc_exchange * fc_port_demux ( struct fc_port *port,
                    836:                                            unsigned int xchg_id ) {
                    837:        struct fc_exchange *xchg;
                    838: 
                    839:        list_for_each_entry ( xchg, &port->xchgs, list ) {
                    840:                if ( xchg->xchg_id == xchg_id )
                    841:                        return xchg;
                    842:        }
                    843:        return NULL;
                    844: }
                    845: 
                    846: /**
                    847:  * Handle received frame from Fibre Channel port
                    848:  *
                    849:  * @v port             Fibre Channel port
                    850:  * @v iobuf            I/O buffer
                    851:  * @v meta             Data transfer metadata
                    852:  * @ret rc             Return status code
                    853:  */
                    854: static int fc_port_deliver ( struct fc_port *port, struct io_buffer *iobuf,
                    855:                             struct xfer_metadata *meta ) {
                    856:        struct fc_frame_header *fchdr = iobuf->data;
                    857:        unsigned int xchg_id;
                    858:        struct fc_exchange *xchg;
                    859:        int rc;
                    860: 
                    861:        /* Sanity check */
                    862:        if ( iob_len ( iobuf ) < sizeof ( *fchdr ) ) {
                    863:                DBGC ( port, "FCPORT %s received underlength frame (%zd "
                    864:                       "bytes)\n", port->name, iob_len ( iobuf ) );
                    865:                rc = -EINVAL;
                    866:                goto err_sanity;
                    867:        }
                    868: 
                    869:        /* Verify local port ID */
                    870:        if ( ( memcmp ( &fchdr->d_id, &port->port_id,
                    871:                        sizeof ( fchdr->d_id ) ) != 0 ) &&
                    872:             ( memcmp ( &fchdr->d_id, &fc_f_port_id,
                    873:                        sizeof ( fchdr->d_id ) ) != 0 ) &&
                    874:             ( memcmp ( &port->port_id, &fc_empty_port_id,
                    875:                        sizeof ( port->port_id ) ) != 0 ) ) {
                    876:                DBGC ( port, "FCPORT %s received frame for incorrect port ID "
                    877:                       "%s\n", port->name, fc_id_ntoa ( &fchdr->d_id ) );
                    878:                rc = -ENOTCONN;
                    879:                goto err_port_id;
                    880:        }
                    881: 
                    882:        /* Demultiplex amongst active exchanges */
                    883:        xchg_id = ntohs ( ( fchdr->f_ctl_es & FC_F_CTL_ES_RESPONDER ) ?
                    884:                          fchdr->ox_id : fchdr->rx_id );
                    885:        xchg = fc_port_demux ( port, xchg_id );
                    886: 
                    887:        /* If we have no active exchange and this frame starts a new
                    888:         * exchange, try to create a new responder exchange
                    889:         */
                    890:        if ( ( fchdr->f_ctl_es & FC_F_CTL_ES_FIRST ) &&
                    891:             ( fchdr->seq_cnt == 0 ) ) {
                    892: 
                    893:                /* Create new exchange */
                    894:                xchg = fc_xchg_respond ( port, fchdr );
                    895:                if ( ! xchg ) {
                    896:                        DBGC ( port, "FCPORT %s cannot create new exchange\n",
                    897:                               port->name );
                    898:                        rc = -ENOMEM;
                    899:                        goto err_respond;
                    900:                }
                    901:        }
                    902: 
                    903:        /* Fail if no exchange exists */
                    904:        if ( ! xchg ) {
                    905:                DBGC ( port, "FCPORT %s xchg %04x unknown\n",
                    906:                       port->name, xchg_id );
                    907:                rc = -ENOTCONN;
                    908:                goto err_no_xchg;
                    909:        }
                    910: 
                    911:        /* Pass received frame to exchange */
                    912:        ref_get ( &xchg->refcnt );
                    913:        if ( ( rc = fc_xchg_rx ( xchg, iob_disown ( iobuf ), meta ) ) != 0 )
                    914:                goto err_xchg_rx;
                    915: 
                    916:  err_xchg_rx:
                    917:        ref_put ( &xchg->refcnt );
                    918:  err_no_xchg:
                    919:  err_respond:
                    920:  err_port_id:
                    921:  err_sanity:
                    922:        free_iob ( iobuf );
                    923:        return rc;
                    924: }
                    925: 
                    926: /**
                    927:  * Log in Fibre Channel port
                    928:  *
                    929:  * @v port             Fibre Channel port
                    930:  * @v port_id          Local port ID
                    931:  * @v link_node_wwn    Link node name
                    932:  * @v link_port_wwn    Link port name
                    933:  * @v has_fabric       Link is to a fabric
                    934:  * @ret rc             Return status code
                    935:  */
                    936: int fc_port_login ( struct fc_port *port, struct fc_port_id *port_id,
                    937:                    const struct fc_name *link_node_wwn,
                    938:                    const struct fc_name *link_port_wwn, int has_fabric ) {
                    939:        struct fc_peer *peer;
                    940:        struct fc_peer *tmp;
                    941:        int rc;
                    942: 
                    943:        /* Perform implicit logout if logged in and details differ */
                    944:        if ( fc_link_ok ( &port->link ) &&
                    945:             ( ( ( !! ( port->flags & FC_PORT_HAS_FABRIC ) ) !=
                    946:                 ( !! has_fabric ) ) ||
                    947:               ( memcmp ( &port->link_node_wwn, link_node_wwn,
                    948:                          sizeof ( port->link_node_wwn ) ) != 0 ) ||
                    949:               ( memcmp ( &port->link_port_wwn, link_port_wwn,
                    950:                          sizeof ( port->link_port_wwn ) ) != 0 ) ||
                    951:               ( has_fabric &&
                    952:                 ( memcmp ( &port->port_id, port_id,
                    953:                            sizeof ( port->port_id ) ) != 0 ) ) ) ) {
                    954:                fc_port_logout ( port, 0 );
                    955:        }
                    956: 
                    957:        /* Log in, if applicable */
                    958:        if ( ! fc_link_ok ( &port->link ) ) {
                    959: 
                    960:                /* Record link port name */
                    961:                memcpy ( &port->link_node_wwn, link_node_wwn,
                    962:                         sizeof ( port->link_node_wwn ) );
                    963:                memcpy ( &port->link_port_wwn, link_port_wwn,
                    964:                         sizeof ( port->link_port_wwn ) );
                    965:                DBGC ( port, "FCPORT %s logged in to %s",
                    966:                       port->name, fc_ntoa ( &port->link_node_wwn ) );
                    967:                DBGC ( port, " port %s\n", fc_ntoa ( &port->link_port_wwn ) );
                    968: 
                    969:                /* Calculate local (and possibly remote) port IDs */
                    970:                if ( has_fabric ) {
                    971:                        port->flags |= FC_PORT_HAS_FABRIC;
                    972:                        memcpy ( &port->port_id, port_id,
                    973:                                 sizeof ( port->port_id ) );
                    974:                } else {
                    975:                        port->flags &= ~FC_PORT_HAS_FABRIC;
                    976:                        if ( memcmp ( &port->port_wwn, link_port_wwn,
                    977:                                      sizeof ( port->port_wwn ) ) > 0 ) {
                    978:                                memcpy ( &port->port_id, &fc_ptp_high_port_id,
                    979:                                         sizeof ( port->port_id ) );
                    980:                                memcpy ( &port->ptp_link_port_id,
                    981:                                         &fc_ptp_low_port_id,
                    982:                                         sizeof ( port->ptp_link_port_id ) );
                    983:                        } else {
                    984:                                memcpy ( &port->port_id, &fc_ptp_low_port_id,
                    985:                                         sizeof ( port->port_id ) );
                    986:                                memcpy ( &port->ptp_link_port_id,
                    987:                                         &fc_ptp_high_port_id,
                    988:                                         sizeof ( port->ptp_link_port_id ) );
                    989:                        }
                    990:                }
                    991:                DBGC ( port, "FCPORT %s logged in via a %s, with local ID "
                    992:                       "%s\n", port->name,
                    993:                       ( ( port->flags & FC_PORT_HAS_FABRIC ) ?
                    994:                         "fabric" : "point-to-point link" ),
                    995:                       fc_id_ntoa ( &port->port_id ) );
                    996:        }
                    997: 
                    998:        /* Log in to name server, if attached to a fabric */
                    999:        if ( has_fabric && ! ( port->flags & FC_PORT_HAS_NS ) ) {
                   1000: 
                   1001:                DBGC ( port, "FCPORT %s attempting login to name server\n",
                   1002:                       port->name );
                   1003: 
                   1004:                intf_restart ( &port->ns_plogi, -ECANCELED );
                   1005:                if ( ( rc = fc_els_plogi ( &port->ns_plogi, port,
                   1006:                                           &fc_gs_port_id ) ) != 0 ) {
                   1007:                        DBGC ( port, "FCPORT %s could not initiate name "
                   1008:                               "server PLOGI: %s\n",
                   1009:                               port->name, strerror ( rc ) );
                   1010:                        fc_port_logout ( port, rc );
                   1011:                        return rc;
                   1012:                }
                   1013:        }
                   1014: 
                   1015:        /* Record login */
                   1016:        fc_link_up ( &port->link );
                   1017: 
                   1018:        /* Notify peers of link state change */
                   1019:        list_for_each_entry_safe ( peer, tmp, &fc_peers, list ) {
                   1020:                fc_peer_get ( peer );
                   1021:                fc_link_examine ( &peer->link );
                   1022:                fc_peer_put ( peer );
                   1023:        }
                   1024: 
                   1025:        return 0;
                   1026: }
                   1027: 
                   1028: /**
                   1029:  * Log out Fibre Channel port
                   1030:  *
                   1031:  * @v port             Fibre Channel port
                   1032:  * @v rc               Reason for logout
                   1033:  */
                   1034: void fc_port_logout ( struct fc_port *port, int rc ) {
                   1035:        struct fc_peer *peer;
                   1036:        struct fc_peer *tmp;
                   1037: 
                   1038:        DBGC ( port, "FCPORT %s logged out: %s\n",
                   1039:               port->name, strerror ( rc ) );
                   1040: 
                   1041:        /* Erase port details */
                   1042:        memset ( &port->port_id, 0, sizeof ( port->port_id ) );
                   1043:        port->flags = 0;
                   1044: 
                   1045:        /* Record logout */
                   1046:        fc_link_err ( &port->link, rc );
                   1047: 
                   1048:        /* Notify peers of link state change */
                   1049:        list_for_each_entry_safe ( peer, tmp, &fc_peers, list ) {
                   1050:                fc_peer_get ( peer );
                   1051:                fc_link_examine ( &peer->link );
                   1052:                fc_peer_put ( peer );
                   1053:        }
                   1054: }
                   1055: 
                   1056: /**
                   1057:  * Handle FLOGI completion
                   1058:  *
                   1059:  * @v port             Fibre Channel port
                   1060:  * @v rc               Reason for completion
                   1061:  */
                   1062: static void fc_port_flogi_done ( struct fc_port *port, int rc ) {
                   1063: 
                   1064:        intf_restart ( &port->flogi, rc );
                   1065: 
                   1066:        if ( rc != 0 )
                   1067:                fc_port_logout ( port, rc );
                   1068: }
                   1069: 
                   1070: /**
                   1071:  * Handle name server PLOGI completion
                   1072:  *
                   1073:  * @v port             Fibre Channel port
                   1074:  * @v rc               Reason for completion
                   1075:  */
                   1076: static void fc_port_ns_plogi_done ( struct fc_port *port, int rc ) {
                   1077: 
                   1078:        intf_restart ( &port->ns_plogi, rc );
                   1079: 
                   1080:        if ( rc == 0 ) {
                   1081:                port->flags |= FC_PORT_HAS_NS;
                   1082:                DBGC ( port, "FCPORT %s logged in to name server\n",
                   1083:                       port->name );
                   1084:        } else {
                   1085:                DBGC ( port, "FCPORT %s could not log in to name server: %s\n",
                   1086:                       port->name, strerror ( rc ) );
                   1087:                /* Absence of a name server is not a fatal error */
                   1088:        }
                   1089: }
                   1090: 
                   1091: /**
                   1092:  * Examine Fibre Channel port link state
                   1093:  *
                   1094:  * @ link              Fibre Channel link state monitor
                   1095:  */
                   1096: static void fc_port_examine ( struct fc_link_state *link ) {
                   1097:        struct fc_port *port = container_of ( link, struct fc_port, link );
                   1098:        int rc;
                   1099: 
                   1100:        /* Do nothing if already logged in */
                   1101:        if ( fc_link_ok ( &port->link ) )
                   1102:                return;
                   1103: 
                   1104:        DBGC ( port, "FCPORT %s attempting login\n", port->name );
                   1105: 
                   1106:        /* Try to create FLOGI ELS */
                   1107:        intf_restart ( &port->flogi, -ECANCELED );
                   1108:        if ( ( rc = fc_els_flogi ( &port->flogi, port ) ) != 0 ) {
                   1109:                DBGC ( port, "FCPORT %s could not initiate FLOGI: %s\n",
                   1110:                       port->name, strerror ( rc ) );
                   1111:                fc_port_logout ( port, rc );
                   1112:                return;
                   1113:        }
                   1114: }
                   1115: 
                   1116: /**
                   1117:  * Handle change of flow control window
                   1118:  *
                   1119:  * @v port             Fibre Channel port
                   1120:  */
                   1121: static void fc_port_window_changed ( struct fc_port *port ) {
                   1122:        size_t window;
                   1123: 
                   1124:        /* Check if transport layer is ready */
                   1125:        window = xfer_window ( &port->transport );
                   1126:        if ( window > 0 ) {
                   1127: 
                   1128:                /* Transport layer is ready.  Start login if the link
                   1129:                 * is not already up.
                   1130:                 */
                   1131:                if ( ! fc_link_ok ( &port->link ) )
                   1132:                        fc_link_start ( &port->link );
                   1133: 
                   1134:        } else {
                   1135: 
                   1136:                /* Transport layer is not ready.  Log out port and
                   1137:                 * wait for transport layer before attempting log in
                   1138:                 * again.
                   1139:                 */
                   1140:                fc_port_logout ( port, -ENOTCONN );
                   1141:                fc_link_stop ( &port->link );
                   1142:        }
                   1143: }
                   1144: 
                   1145: /** Fibre Channel port transport interface operations */
                   1146: static struct interface_operation fc_port_transport_op[] = {
                   1147:        INTF_OP ( xfer_deliver, struct fc_port *, fc_port_deliver ),
                   1148:        INTF_OP ( xfer_window_changed, struct fc_port *,
                   1149:                  fc_port_window_changed ),
                   1150:        INTF_OP ( intf_close, struct fc_port *, fc_port_close ),
                   1151: };
                   1152: 
                   1153: /** Fibre Channel port transport interface descriptor */
                   1154: static struct interface_descriptor fc_port_transport_desc =
                   1155:        INTF_DESC ( struct fc_port, transport, fc_port_transport_op );
                   1156: 
                   1157: /** Fibre Channel port FLOGI interface operations */
                   1158: static struct interface_operation fc_port_flogi_op[] = {
                   1159:        INTF_OP ( intf_close, struct fc_port *, fc_port_flogi_done ),
                   1160: };
                   1161: 
                   1162: /** Fibre Channel port FLOGI interface descriptor */
                   1163: static struct interface_descriptor fc_port_flogi_desc =
                   1164:        INTF_DESC ( struct fc_port, flogi, fc_port_flogi_op );
                   1165: 
                   1166: /** Fibre Channel port name server PLOGI interface operations */
                   1167: static struct interface_operation fc_port_ns_plogi_op[] = {
                   1168:        INTF_OP ( intf_close, struct fc_port *, fc_port_ns_plogi_done ),
                   1169: };
                   1170: 
                   1171: /** Fibre Channel port name server PLOGI interface descriptor */
                   1172: static struct interface_descriptor fc_port_ns_plogi_desc =
                   1173:        INTF_DESC ( struct fc_port, ns_plogi, fc_port_ns_plogi_op );
                   1174: 
                   1175: /**
                   1176:  * Create Fibre Channel port
                   1177:  *
                   1178:  * @v transport                Transport interface
                   1179:  * @v node             Fibre Channel node name
                   1180:  * @v port             Fibre Channel port name
                   1181:  * @v name             Symbolic port name
                   1182:  * @ret rc             Return status code
                   1183:  */
                   1184: int fc_port_open ( struct interface *transport, const struct fc_name *node_wwn,
                   1185:                   const struct fc_name *port_wwn, const char *name ) {
                   1186:        struct fc_port *port;
                   1187: 
                   1188:        /* Allocate and initialise structure */
                   1189:        port = zalloc ( sizeof ( *port ) );
                   1190:        if ( ! port )
                   1191:                return -ENOMEM;
                   1192:        ref_init ( &port->refcnt, NULL );
                   1193:        intf_init ( &port->transport, &fc_port_transport_desc, &port->refcnt );
                   1194:        fc_link_init ( &port->link, fc_port_examine, &port->refcnt );
                   1195:        intf_init ( &port->flogi, &fc_port_flogi_desc, &port->refcnt );
                   1196:        intf_init ( &port->ns_plogi, &fc_port_ns_plogi_desc, &port->refcnt );
                   1197:        list_add_tail ( &port->list, &fc_ports );
                   1198:        INIT_LIST_HEAD ( &port->xchgs );
                   1199:        memcpy ( &port->node_wwn, node_wwn, sizeof ( port->node_wwn ) );
                   1200:        memcpy ( &port->port_wwn, port_wwn, sizeof ( port->port_wwn ) );
                   1201:        snprintf ( port->name, sizeof ( port->name ), "%s", name );
                   1202: 
                   1203:        DBGC ( port, "FCPORT %s opened as %s",
                   1204:               port->name, fc_ntoa ( &port->node_wwn ) );
                   1205:        DBGC ( port, " port %s\n", fc_ntoa ( &port->port_wwn ) );
                   1206: 
                   1207:        /* Attach to transport layer, mortalise self, and return */
                   1208:        intf_plug_plug ( &port->transport, transport );
                   1209:        ref_put ( &port->refcnt );
                   1210:        return 0;
                   1211: }
                   1212: 
                   1213: /**
                   1214:  * Find Fibre Channel port by name
                   1215:  *
                   1216:  * @v name             Fibre Channel port name
                   1217:  * @ret port           Fibre Channel port, or NULL
                   1218:  */
                   1219: struct fc_port * fc_port_find ( const char *name ) {
                   1220:        struct fc_port *port;
                   1221: 
                   1222:        list_for_each_entry ( port, &fc_ports, list ) {
                   1223:                if ( strcmp ( name, port->name ) == 0 )
                   1224:                        return port;
                   1225:        }
                   1226:        return NULL;
                   1227: }
                   1228: 
                   1229: /******************************************************************************
                   1230:  *
                   1231:  * Fibre Channel peers
                   1232:  *
                   1233:  ******************************************************************************
                   1234:  */
                   1235: 
                   1236: /**
                   1237:  * Close Fibre Channel peer
                   1238:  *
                   1239:  * @v peer             Fibre Channel peer
                   1240:  * @v rc               Reason for close
                   1241:  */
                   1242: static void fc_peer_close ( struct fc_peer *peer, int rc ) {
                   1243: 
                   1244:        DBGC ( peer, "FCPEER %s closed: %s\n",
                   1245:               fc_ntoa ( &peer->port_wwn ) , strerror ( rc ) );
                   1246: 
                   1247:        /* Sanity check */
                   1248:        assert ( list_empty ( &peer->ulps ) );
                   1249: 
                   1250:        /* Stop link timer */
                   1251:        fc_link_stop ( &peer->link );
                   1252: 
                   1253:        /* Shut down interfaces */
                   1254:        intf_shutdown ( &peer->plogi, rc );
                   1255: 
                   1256:        /* Remove from list of peers */
                   1257:        list_del ( &peer->list );
                   1258:        INIT_LIST_HEAD ( &peer->list );
                   1259: }
                   1260: 
                   1261: /**
                   1262:  * Increment Fibre Channel peer active usage count
                   1263:  *
                   1264:  * @v peer             Fibre Channel peer
                   1265:  */
                   1266: static void fc_peer_increment ( struct fc_peer *peer ) {
                   1267: 
                   1268:        /* Increment our usage count */
                   1269:        peer->usage++;
                   1270: }
                   1271: 
                   1272: /**
                   1273:  * Decrement Fibre Channel peer active usage count
                   1274:  *
                   1275:  * @v peer             Fibre Channel peer
                   1276:  */
                   1277: static void fc_peer_decrement ( struct fc_peer *peer ) {
                   1278: 
                   1279:        /* Sanity check */
                   1280:        assert ( peer->usage > 0 );
                   1281: 
                   1282:        /* Decrement our usage count and log out if we reach zero */
                   1283:        if ( --(peer->usage) == 0 )
                   1284:                fc_peer_logout ( peer, 0 );
                   1285: }
                   1286: 
                   1287: /**
                   1288:  * Log in Fibre Channel peer
                   1289:  *
                   1290:  * @v peer             Fibre Channel peer
                   1291:  * @v port             Fibre Channel port
                   1292:  * @v port_id          Port ID
                   1293:  * @ret rc             Return status code
                   1294:  */
                   1295: int fc_peer_login ( struct fc_peer *peer, struct fc_port *port,
                   1296:                    struct fc_port_id *port_id ) {
                   1297:        struct fc_ulp *ulp;
                   1298:        struct fc_ulp *tmp;
                   1299: 
                   1300:        /* Perform implicit logout if logged in and details differ */
                   1301:        if ( fc_link_ok ( &peer->link ) &&
                   1302:             ( ( peer->port != port ) ||
                   1303:               ( memcmp ( &peer->port_id, port_id,
                   1304:                          sizeof ( peer->port_id ) ) !=0 ) ) ) {
                   1305:                fc_peer_logout ( peer, 0 );
                   1306:        }
                   1307: 
                   1308:        /* Log in, if applicable */
                   1309:        if ( ! fc_link_ok ( &peer->link ) ) {
                   1310: 
                   1311:                /* Record peer details */
                   1312:                assert ( peer->port == NULL );
                   1313:                peer->port = fc_port_get ( port );
                   1314:                memcpy ( &peer->port_id, port_id, sizeof ( peer->port_id ) );
                   1315:                DBGC ( peer, "FCPEER %s logged in via %s as %s\n",
                   1316:                       fc_ntoa ( &peer->port_wwn ), peer->port->name,
                   1317:                       fc_id_ntoa ( &peer->port_id ) );
                   1318: 
                   1319:                /* Add login reference */
                   1320:                fc_peer_get ( peer );
                   1321:        }
                   1322: 
                   1323:        /* Record login */
                   1324:        fc_link_up ( &peer->link );
                   1325: 
                   1326:        /* Notify ULPs of link state change */
                   1327:        list_for_each_entry_safe ( ulp, tmp, &peer->ulps, list ) {
                   1328:                fc_ulp_get ( ulp );
                   1329:                fc_link_examine ( &ulp->link );
                   1330:                fc_ulp_put ( ulp );
                   1331:        }
                   1332: 
                   1333:        return 0;
                   1334: }
                   1335: 
                   1336: /**
                   1337:  * Log out Fibre Channel peer
                   1338:  *
                   1339:  * @v peer             Fibre Channel peer
                   1340:  * @v rc               Reason for logout
                   1341:  */
                   1342: void fc_peer_logout ( struct fc_peer *peer, int rc ) {
                   1343:        struct fc_ulp *ulp;
                   1344:        struct fc_ulp *tmp;
                   1345: 
                   1346:        DBGC ( peer, "FCPEER %s logged out: %s\n",
                   1347:               fc_ntoa ( &peer->port_wwn ), strerror ( rc ) );
                   1348: 
                   1349:        /* Drop login reference, if applicable */
                   1350:        if ( fc_link_ok ( &peer->link ) )
                   1351:                fc_peer_put ( peer );
                   1352: 
                   1353:        /* Erase peer details */
                   1354:        fc_port_put ( peer->port );
                   1355:        peer->port = NULL;
                   1356: 
                   1357:        /* Record logout */
                   1358:        fc_link_err ( &peer->link, rc );
                   1359: 
                   1360:        /* Notify ULPs of link state change */
                   1361:        list_for_each_entry_safe ( ulp, tmp, &peer->ulps, list ) {
                   1362:                fc_ulp_get ( ulp );
                   1363:                fc_link_examine ( &ulp->link );
                   1364:                fc_ulp_put ( ulp );
                   1365:        }
                   1366: 
                   1367:        /* Close peer if there are no active users */
                   1368:        if ( peer->usage == 0 )
                   1369:                fc_peer_close ( peer, rc );
                   1370: }
                   1371: 
                   1372: /**
                   1373:  * Handle PLOGI completion
                   1374:  *
                   1375:  * @v peer             Fibre Channel peer
                   1376:  * @v rc               Reason for completion
                   1377:  */
                   1378: static void fc_peer_plogi_done ( struct fc_peer *peer, int rc ) {
                   1379: 
                   1380:        intf_restart ( &peer->plogi, rc );
                   1381: 
                   1382:        if ( rc != 0 )
                   1383:                fc_peer_logout ( peer, rc );
                   1384: }
                   1385: 
                   1386: /**
                   1387:  * Initiate PLOGI
                   1388:  *
                   1389:  * @v peer             Fibre Channel peer
                   1390:  * @v port             Fibre Channel port
                   1391:  * @v peer_port_id     Peer port ID
                   1392:  * @ret rc             Return status code
                   1393:  */
                   1394: static int fc_peer_plogi ( struct fc_peer *peer, struct fc_port *port,
                   1395:                           struct fc_port_id *peer_port_id ) {
                   1396:        int rc;
                   1397: 
                   1398:        /* Try to create PLOGI ELS */
                   1399:        intf_restart ( &peer->plogi, -ECANCELED );
                   1400:        if ( ( rc = fc_els_plogi ( &peer->plogi, port, peer_port_id ) ) != 0 ) {
                   1401:                DBGC ( peer, "FCPEER %s could not initiate PLOGI: %s\n",
                   1402:                       fc_ntoa ( &peer->port_wwn ), strerror ( rc ) );
                   1403:                fc_peer_logout ( peer, rc );
                   1404:                return rc;
                   1405:        }
                   1406: 
                   1407:        return 0;
                   1408: }
                   1409: 
                   1410: /**
                   1411:  * Examine Fibre Channel peer link state
                   1412:  *
                   1413:  * @ link              Fibre Channel link state monitor
                   1414:  */
                   1415: static void fc_peer_examine ( struct fc_link_state *link ) {
                   1416:        struct fc_peer *peer = container_of ( link, struct fc_peer, link );
                   1417:        struct fc_port *port;
                   1418:        int rc;
                   1419: 
                   1420:        /* Check to see if underlying port link has gone down */
                   1421:        if ( peer->port && ( ! fc_link_ok ( &peer->port->link ) ) ) {
                   1422:                fc_peer_logout ( peer, -ENOTCONN );
                   1423:                return;
                   1424:        }
                   1425: 
                   1426:        /* Do nothing if already logged in */
                   1427:        if ( fc_link_ok ( &peer->link ) )
                   1428:                return;
                   1429: 
                   1430:        DBGC ( peer, "FCPEER %s attempting login\n",
                   1431:               fc_ntoa ( &peer->port_wwn ) );
                   1432: 
                   1433:        /* Sanity check */
                   1434:        assert ( peer->port == NULL );
                   1435: 
                   1436:        /* First, look for a port with the peer attached via a
                   1437:         * point-to-point link.
                   1438:         */
                   1439:        list_for_each_entry ( port, &fc_ports, list ) {
                   1440:                if ( fc_link_ok ( &port->link ) &&
                   1441:                     ( ! ( port->flags & FC_PORT_HAS_FABRIC ) ) &&
                   1442:                     ( memcmp ( &peer->port_wwn, &port->link_port_wwn,
                   1443:                                sizeof ( peer->port_wwn ) ) == 0 ) ) {
                   1444:                        /* Use this peer port ID, and stop looking */
                   1445:                        fc_peer_plogi ( peer, port, &port->ptp_link_port_id );
                   1446:                        return;
                   1447:                }
                   1448:        }
                   1449: 
                   1450:        /* If the peer is not directly attached, try initiating a name
                   1451:         * server lookup on any suitable ports.
                   1452:         */
                   1453:        list_for_each_entry ( port, &fc_ports, list ) {
                   1454:                if ( fc_link_ok ( &port->link ) &&
                   1455:                     ( port->flags & FC_PORT_HAS_FABRIC ) &&
                   1456:                     ( port->flags & FC_PORT_HAS_NS ) ) {
                   1457:                        if ( ( rc = fc_ns_query ( peer, port,
                   1458:                                                  fc_peer_plogi ) ) != 0 ) {
                   1459:                                DBGC ( peer, "FCPEER %s could not attempt "
                   1460:                                       "name server lookup on %s: %s\n",
                   1461:                                       fc_ntoa ( &peer->port_wwn ), port->name,
                   1462:                                       strerror ( rc ) );
                   1463:                                /* Non-fatal */
                   1464:                        }
                   1465:                }
                   1466:        }
                   1467: }
                   1468: 
                   1469: /** Fibre Channel peer PLOGI interface operations */
                   1470: static struct interface_operation fc_peer_plogi_op[] = {
                   1471:        INTF_OP ( intf_close, struct fc_peer *, fc_peer_plogi_done ),
                   1472: };
                   1473: 
                   1474: /** Fibre Channel peer PLOGI interface descriptor */
                   1475: static struct interface_descriptor fc_peer_plogi_desc =
                   1476:        INTF_DESC ( struct fc_peer, plogi, fc_peer_plogi_op );
                   1477: 
                   1478: /**
                   1479:  * Create Fibre Channel peer
                   1480:  *
                   1481:  * @v port_wwn         Node name
                   1482:  * @ret peer           Fibre Channel peer, or NULL
                   1483:  */
                   1484: static struct fc_peer * fc_peer_create ( const struct fc_name *port_wwn ) {
                   1485:        struct fc_peer *peer;
                   1486: 
                   1487:        /* Allocate and initialise structure */
                   1488:        peer = zalloc ( sizeof ( *peer ) );
                   1489:        if ( ! peer )
                   1490:                return NULL;
                   1491:        ref_init ( &peer->refcnt, NULL );
                   1492:        fc_link_init ( &peer->link, fc_peer_examine, &peer->refcnt );
                   1493:        intf_init ( &peer->plogi, &fc_peer_plogi_desc, &peer->refcnt );
                   1494:        list_add_tail ( &peer->list, &fc_peers );
                   1495:        memcpy ( &peer->port_wwn, port_wwn, sizeof ( peer->port_wwn ) );
                   1496:        INIT_LIST_HEAD ( &peer->ulps );
                   1497: 
                   1498:        /* Start link monitor */
                   1499:        fc_link_start ( &peer->link );
                   1500: 
                   1501:        DBGC ( peer, "FCPEER %s created\n", fc_ntoa ( &peer->port_wwn ) );
                   1502:        return peer;
                   1503: }
                   1504: 
                   1505: /**
                   1506:  * Get Fibre Channel peer by node name
                   1507:  *
                   1508:  * @v port_wwn         Node name
                   1509:  * @ret peer           Fibre Channel peer, or NULL
                   1510:  */
                   1511: struct fc_peer * fc_peer_get_wwn ( const struct fc_name *port_wwn ) {
                   1512:        struct fc_peer *peer;
                   1513: 
                   1514:        /* Look for an existing peer */
                   1515:        list_for_each_entry ( peer, &fc_peers, list ) {
                   1516:                if ( memcmp ( &peer->port_wwn, port_wwn,
                   1517:                              sizeof ( peer->port_wwn ) ) == 0 )
                   1518:                        return fc_peer_get ( peer );
                   1519:        }
                   1520: 
                   1521:        /* Create a new peer */
                   1522:        peer = fc_peer_create ( port_wwn );
                   1523:        if ( ! peer )
                   1524:                return NULL;
                   1525: 
                   1526:        return peer;
                   1527: }
                   1528: 
                   1529: /**
                   1530:  * Get Fibre Channel peer by port ID
                   1531:  *
                   1532:  * @v port             Fibre Channel port
                   1533:  * @v peer_port_id     Peer port ID
                   1534:  * @ret peer           Fibre Channel peer, or NULL
                   1535:  */
                   1536: struct fc_peer * fc_peer_get_port_id ( struct fc_port *port,
                   1537:                                       const struct fc_port_id *peer_port_id ){
                   1538:        struct fc_peer *peer;
                   1539: 
                   1540:        /* Look for an existing peer */
                   1541:        list_for_each_entry ( peer, &fc_peers, list ) {
                   1542:                if ( ( peer->port == port ) &&
                   1543:                     ( memcmp ( &peer->port_id, peer_port_id,
                   1544:                                sizeof ( peer->port_id ) ) == 0 ) )
                   1545:                        return fc_peer_get ( peer );
                   1546:        }
                   1547: 
                   1548:        /* Cannot create a new peer, since we have no port name to use */
                   1549:        return NULL;
                   1550: }
                   1551: 
                   1552: /******************************************************************************
                   1553:  *
                   1554:  * Fibre Channel upper-layer protocols
                   1555:  *
                   1556:  ******************************************************************************
                   1557:  */
                   1558: 
                   1559: /**
                   1560:  * Free Fibre Channel upper-layer protocol
                   1561:  *
                   1562:  * @v refcnt           Reference count
                   1563:  */
                   1564: static void fc_ulp_free ( struct refcnt *refcnt ) {
                   1565:        struct fc_ulp *ulp = container_of ( refcnt, struct fc_ulp, refcnt );
                   1566: 
                   1567:        fc_peer_put ( ulp->peer );
                   1568:        free ( ulp );
                   1569: }
                   1570: 
                   1571: /**
                   1572:  * Close Fibre Channel upper-layer protocol
                   1573:  *
                   1574:  * @v ulp              Fibre Channel upper-layer protocol
                   1575:  * @v rc               Reason for close
                   1576:  */
                   1577: static void fc_ulp_close ( struct fc_ulp *ulp, int rc ) {
                   1578: 
                   1579:        DBGC ( ulp, "FCULP %s/%02x closed: %s\n",
                   1580:               fc_ntoa ( &ulp->peer->port_wwn ), ulp->type, strerror ( rc ) );
                   1581: 
                   1582:        /* Sanity check */
                   1583:        assert ( ulp->usage == 0 );
                   1584: 
                   1585:        /* Stop link monitor */
                   1586:        fc_link_stop ( &ulp->link );
                   1587: 
                   1588:        /* Shut down interfaces */
                   1589:        intf_shutdown ( &ulp->prli, rc );
                   1590: 
                   1591:        /* Remove from list of ULPs */
                   1592:        list_del ( &ulp->list );
                   1593:        INIT_LIST_HEAD ( &ulp->list );
                   1594: }
                   1595: 
                   1596: /**
                   1597:  * Increment Fibre Channel upper-layer protocol active usage count
                   1598:  *
                   1599:  * @v ulp              Fibre Channel ulp
                   1600:  */
                   1601: void fc_ulp_increment ( struct fc_ulp *ulp ) {
                   1602: 
                   1603:        /* Increment peer's usage count */
                   1604:        fc_peer_increment ( ulp->peer );
                   1605: 
                   1606:        /* Increment our usage count */
                   1607:        ulp->usage++;
                   1608: }
                   1609: 
                   1610: /**
                   1611:  * Decrement Fibre Channel upper-layer protocol active usage count
                   1612:  *
                   1613:  * @v ulp              Fibre Channel ulp
                   1614:  */
                   1615: void fc_ulp_decrement ( struct fc_ulp *ulp ) {
                   1616: 
                   1617:        /* Sanity check */
                   1618:        assert ( ulp->usage > 0 );
                   1619: 
                   1620:        /* Decrement our usage count and log out if we reach zero */
                   1621:        if ( --(ulp->usage) == 0 )
                   1622:                fc_ulp_logout ( ulp, 0 );
                   1623: 
                   1624:        /* Decrement our peer's usage count */
                   1625:        fc_peer_decrement ( ulp->peer );
                   1626: }
                   1627: 
                   1628: /**
                   1629:  * Log in Fibre Channel upper-layer protocol
                   1630:  *
                   1631:  * @v ulp              Fibre Channel upper-layer protocol
                   1632:  * @v param            Service parameters
                   1633:  * @v param_len                Length of service parameters
                   1634:  * @v originated       Login was originated by us
                   1635:  * @ret rc             Return status code
                   1636:  */
                   1637: int fc_ulp_login ( struct fc_ulp *ulp, const void *param, size_t param_len,
                   1638:                   int originated ) {
                   1639: 
                   1640:        /* Perform implicit logout if logged in and service parameters differ */
                   1641:        if ( fc_link_ok ( &ulp->link ) &&
                   1642:             ( ( ulp->param_len != param_len ) ||
                   1643:               ( memcmp ( ulp->param, param, ulp->param_len ) != 0 ) ) ) {
                   1644:                fc_ulp_logout ( ulp, 0 );
                   1645:        }
                   1646: 
                   1647:        /* Log in, if applicable */
                   1648:        if ( ! fc_link_ok ( &ulp->link ) ) {
                   1649: 
                   1650:                /* Record service parameters */
                   1651:                assert ( ulp->param == NULL );
                   1652:                assert ( ulp->param_len == 0 );
                   1653:                ulp->param = malloc ( param_len );
                   1654:                if ( ! ulp->param ) {
                   1655:                        DBGC ( ulp, "FCULP %s/%02x could not record "
                   1656:                               "parameters\n",
                   1657:                               fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
                   1658:                        return -ENOMEM;
                   1659:                }
                   1660:                memcpy ( ulp->param, param, param_len );
                   1661:                ulp->param_len = param_len;
                   1662:                DBGC ( ulp, "FCULP %s/%02x logged in with parameters:\n",
                   1663:                       fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
                   1664:                DBGC_HDA ( ulp, 0, ulp->param, ulp->param_len );
                   1665: 
                   1666:                /* Add login reference */
                   1667:                fc_ulp_get ( ulp );
                   1668:        }
                   1669: 
                   1670:        /* Record login */
                   1671:        fc_link_up ( &ulp->link );
                   1672: 
                   1673:        /* Work around a bug in some versions of the Linux Fibre
                   1674:         * Channel stack, which fail to fully initialise image pairs
                   1675:         * established via a PRLI originated by the Linux stack
                   1676:         * itself.
                   1677:         */
                   1678:        if ( originated )
                   1679:                ulp->flags |= FC_ULP_ORIGINATED_LOGIN_OK;
                   1680:        if ( ! ( ulp->flags & FC_ULP_ORIGINATED_LOGIN_OK ) ) {
                   1681:                DBGC ( ulp, "FCULP %s/%02x sending extra PRLI to work around "
                   1682:                       "Linux bug\n",
                   1683:                       fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
                   1684:                fc_link_start ( &ulp->link );
                   1685:        }
                   1686: 
                   1687:        return 0;
                   1688: }
                   1689: 
                   1690: /**
                   1691:  * Log out Fibre Channel upper-layer protocol
                   1692:  *
                   1693:  * @v ulp              Fibre Channel upper-layer protocol
                   1694:  * @v rc               Reason for logout
                   1695:  */
                   1696: void fc_ulp_logout ( struct fc_ulp *ulp, int rc ) {
                   1697: 
                   1698:        DBGC ( ulp, "FCULP %s/%02x logged out: %s\n",
                   1699:               fc_ntoa ( &ulp->peer->port_wwn ), ulp->type, strerror ( rc ) );
                   1700: 
                   1701:        /* Drop login reference, if applicable */
                   1702:        if ( fc_link_ok ( &ulp->link ) )
                   1703:                fc_ulp_put ( ulp );
                   1704: 
                   1705:        /* Discard service parameters */
                   1706:        free ( ulp->param );
                   1707:        ulp->param = NULL;
                   1708:        ulp->param_len = 0;
                   1709:        ulp->flags = 0;
                   1710: 
                   1711:        /* Record logout */
                   1712:        fc_link_err ( &ulp->link, rc );
                   1713: 
                   1714:        /* Close ULP if there are no clients attached */
                   1715:        if ( ulp->usage == 0 )
                   1716:                fc_ulp_close ( ulp, rc );
                   1717: }
                   1718: 
                   1719: /**
                   1720:  * Handle PRLI completion
                   1721:  *
                   1722:  * @v ulp              Fibre Channel upper-layer protocol
                   1723:  * @v rc               Reason for completion
                   1724:  */
                   1725: static void fc_ulp_prli_done ( struct fc_ulp *ulp, int rc ) {
                   1726: 
                   1727:        intf_restart ( &ulp->prli, rc );
                   1728: 
                   1729:        if ( rc != 0 )
                   1730:                fc_ulp_logout ( ulp, rc );
                   1731: }
                   1732: 
                   1733: /**
                   1734:  * Examine Fibre Channel upper-layer protocol link state
                   1735:  *
                   1736:  * @ link              Fibre Channel link state monitor
                   1737:  */
                   1738: static void fc_ulp_examine ( struct fc_link_state *link ) {
                   1739:        struct fc_ulp *ulp = container_of ( link, struct fc_ulp, link );
                   1740:        int rc;
                   1741: 
                   1742:        /* Check to see if underlying peer link has gone down */
                   1743:        if ( ! fc_link_ok ( &ulp->peer->link ) ) {
                   1744:                fc_ulp_logout ( ulp, -ENOTCONN );
                   1745:                return;
                   1746:        }
                   1747: 
                   1748:        /* Do nothing if already logged in */
                   1749:        if ( fc_link_ok ( &ulp->link ) &&
                   1750:             ( ulp->flags & FC_ULP_ORIGINATED_LOGIN_OK ) )
                   1751:                return;
                   1752: 
                   1753:        DBGC ( ulp, "FCULP %s/%02x attempting login\n",
                   1754:               fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
                   1755: 
                   1756:        /* Try to create PRLI ELS */
                   1757:        intf_restart ( &ulp->prli, -ECANCELED );
                   1758:        if ( ( rc = fc_els_prli ( &ulp->prli, ulp->peer->port,
                   1759:                                  &ulp->peer->port_id, ulp->type ) ) != 0 ) {
                   1760:                DBGC ( ulp, "FCULP %s/%02x could not initiate PRLI: %s\n",
                   1761:                       fc_ntoa ( &ulp->peer->port_wwn ), ulp->type,
                   1762:                       strerror ( rc ) );
                   1763:                fc_ulp_logout ( ulp, rc );
                   1764:                return;
                   1765:        }
                   1766: }
                   1767: 
                   1768: /** Fibre Channel upper-layer protocol PRLI interface operations */
                   1769: static struct interface_operation fc_ulp_prli_op[] = {
                   1770:        INTF_OP ( intf_close, struct fc_ulp *, fc_ulp_prli_done ),
                   1771: };
                   1772: 
                   1773: /** Fibre Channel upper-layer protocol PRLI interface descriptor */
                   1774: static struct interface_descriptor fc_ulp_prli_desc =
                   1775:        INTF_DESC ( struct fc_ulp, prli, fc_ulp_prli_op );
                   1776: 
                   1777: /**
                   1778:  * Create Fibre Channel upper-layer protocl
                   1779:  *
                   1780:  * @v peer             Fibre Channel peer
                   1781:  * @v type             Type
                   1782:  * @ret ulp            Fibre Channel upper-layer protocol, or NULL
                   1783:  */
                   1784: static struct fc_ulp * fc_ulp_create ( struct fc_peer *peer,
                   1785:                                       unsigned int type ) {
                   1786:        struct fc_ulp *ulp;
                   1787: 
                   1788:        /* Allocate and initialise structure */
                   1789:        ulp = zalloc ( sizeof ( *ulp ) );
                   1790:        if ( ! ulp )
                   1791:                return NULL;
                   1792:        ref_init ( &ulp->refcnt, fc_ulp_free );
                   1793:        fc_link_init ( &ulp->link, fc_ulp_examine, &ulp->refcnt );
                   1794:        intf_init ( &ulp->prli, &fc_ulp_prli_desc, &ulp->refcnt );
                   1795:        ulp->peer = fc_peer_get ( peer );
                   1796:        list_add_tail ( &ulp->list, &peer->ulps );
                   1797:        ulp->type = type;
                   1798: 
                   1799:        /* Start link state monitor */
                   1800:        fc_link_start ( &ulp->link );
                   1801: 
                   1802:        DBGC ( ulp, "FCULP %s/%02x created\n",
                   1803:               fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
                   1804:        return ulp;
                   1805: }
                   1806: 
                   1807: /**
                   1808:  * Get Fibre Channel upper-layer protocol by peer and type
                   1809:  *
                   1810:  * @v peer             Fibre Channel peer
                   1811:  * @v type             Type
                   1812:  * @ret ulp            Fibre Channel upper-layer protocol, or NULL
                   1813:  */
                   1814: static struct fc_ulp * fc_ulp_get_type ( struct fc_peer *peer,
                   1815:                                         unsigned int type ) {
                   1816:        struct fc_ulp *ulp;
                   1817: 
                   1818:        /* Look for an existing ULP */
                   1819:        list_for_each_entry ( ulp, &peer->ulps, list ) {
                   1820:                if ( ulp->type == type )
                   1821:                        return fc_ulp_get ( ulp );
                   1822:        }
                   1823: 
                   1824:        /* Create a new ULP */
                   1825:        ulp = fc_ulp_create ( peer, type );
                   1826:        if ( ! ulp )
                   1827:                return NULL;
                   1828: 
                   1829:        return ulp;
                   1830: }
                   1831: 
                   1832: /**
                   1833:  * Get Fibre Channel upper-layer protocol by port name and type
                   1834:  *
                   1835:  * @v port_wwn         Port name
                   1836:  * @v type             Type
                   1837:  * @ret ulp            Fibre Channel upper-layer protocol, or NULL
                   1838:  */
                   1839: struct fc_ulp * fc_ulp_get_wwn_type ( const struct fc_name *port_wwn,
                   1840:                                      unsigned int type ) {
                   1841:        struct fc_ulp *ulp;
                   1842:        struct fc_peer *peer;
                   1843: 
                   1844:        /* Get peer */
                   1845:        peer = fc_peer_get_wwn ( port_wwn );
                   1846:        if ( ! peer )
                   1847:                goto err_peer_get_wwn;
                   1848: 
                   1849:        /* Get ULP */
                   1850:        ulp = fc_ulp_get_type ( peer, type );
                   1851:        if ( ! ulp )
                   1852:                goto err_ulp_get_type;
                   1853: 
                   1854:        /* Drop temporary reference to peer */
                   1855:        fc_peer_put ( peer );
                   1856: 
                   1857:        return ulp;
                   1858: 
                   1859:        fc_ulp_put ( ulp );
                   1860:  err_ulp_get_type:
                   1861:        fc_peer_put ( peer );
                   1862:  err_peer_get_wwn:
                   1863:        return NULL;
                   1864: }
                   1865: 
                   1866: /**
                   1867:  * Get Fibre Channel upper-layer protocol by port ID and type
                   1868:  *
                   1869:  * @v port             Fibre Channel port
                   1870:  * @v peer_port_id     Peer port ID
                   1871:  * @v type             Type
                   1872:  * @ret ulp            Fibre Channel upper-layer protocol, or NULL
                   1873:  */
                   1874: struct fc_ulp * fc_ulp_get_port_id_type ( struct fc_port *port,
                   1875:                                          const struct fc_port_id *peer_port_id,
                   1876:                                          unsigned int type ) {
                   1877:        struct fc_ulp *ulp;
                   1878:        struct fc_peer *peer;
                   1879: 
                   1880:        /* Get peer */
                   1881:        peer = fc_peer_get_port_id ( port, peer_port_id );
                   1882:        if ( ! peer )
                   1883:                goto err_peer_get_wwn;
                   1884: 
                   1885:        /* Get ULP */
                   1886:        ulp = fc_ulp_get_type ( peer, type );
                   1887:        if ( ! ulp )
                   1888:                goto err_ulp_get_type;
                   1889: 
                   1890:        /* Drop temporary reference to peer */
                   1891:        fc_peer_put ( peer );
                   1892: 
                   1893:        return ulp;
                   1894: 
                   1895:        fc_ulp_put ( ulp );
                   1896:  err_ulp_get_type:
                   1897:        fc_peer_put ( peer );
                   1898:  err_peer_get_wwn:
                   1899:        return NULL;
                   1900: }

unix.superglobalmegacorp.com

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