Annotation of qemu/roms/ipxe/src/net/fcels.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 <stdint.h>
                     22: #include <stdlib.h>
                     23: #include <string.h>
                     24: #include <errno.h>
                     25: #include <assert.h>
                     26: #include <byteswap.h>
                     27: #include <ipxe/interface.h>
                     28: #include <ipxe/xfer.h>
                     29: #include <ipxe/iobuf.h>
                     30: #include <ipxe/process.h>
                     31: #include <ipxe/fc.h>
                     32: #include <ipxe/fcels.h>
                     33: 
                     34: /** @file
                     35:  *
                     36:  * Fibre Channel Extended Link Services
                     37:  *
                     38:  */
                     39: 
                     40: /** Fibre Channel ELS transaction debug message format */
                     41: #define FCELS_FMT "FCELS %s %s %s %s"
                     42: 
                     43: /** Fibre Channel ELS transaction debug message arguments */
                     44: #define FCELS_ARGS( els )                                              \
                     45:        (els)->port->name,                                              \
                     46:        ( (els)->handler ? (els)->handler->name : "unknown ELS" ),      \
                     47:        ( fc_els_is_request ( els ) ? "to" : "from" ),                  \
                     48:        fc_id_ntoa ( &(els)->peer_port_id )
                     49: 
                     50: struct fc_els_handler fc_els_unknown_handler __fc_els_handler;
                     51: 
                     52: /**
                     53:  * Free Fibre Channel ELS transaction
                     54:  *
                     55:  * @v refcnt           Reference count
                     56:  */
                     57: static void fc_els_free ( struct refcnt *refcnt ) {
                     58:        struct fc_els *els = container_of ( refcnt, struct fc_els, refcnt );
                     59: 
                     60:        assert ( ! process_running ( &els->process ) );
                     61:        fc_port_put ( els->port );
                     62:        free ( els );
                     63: }
                     64: 
                     65: /**
                     66:  * Close Fibre Channel ELS transaction
                     67:  *
                     68:  * @v els              Fibre Channel ELS transaction
                     69:  * @v rc               Reason for close
                     70:  */
                     71: static void fc_els_close ( struct fc_els *els, int rc ) {
                     72: 
                     73:        if ( rc != 0 ) {
                     74:                DBGC ( els, FCELS_FMT " complete (%s)\n",
                     75:                       FCELS_ARGS ( els ), strerror ( rc ) );
                     76:        }
                     77: 
                     78:        /* Stop process */
                     79:        process_del ( &els->process );
                     80: 
                     81:        /* Shut down interfaces */
                     82:        intf_shutdown ( &els->xchg, rc );
                     83:        intf_shutdown ( &els->job, rc );
                     84: }
                     85: 
                     86: /**
                     87:  * Detect Fibre Channel ELS frame handler
                     88:  *
                     89:  * @v els              Fibre Channel ELS transaction
                     90:  * @v command          ELS command code
                     91:  * @ret handler                ELS handler, or NULL
                     92:  */
                     93: static struct fc_els_handler * fc_els_detect ( struct fc_els *els,
                     94:                                               const void *data,
                     95:                                               size_t len ) {
                     96:        const struct fc_els_frame_common *frame = data;
                     97:        struct fc_els_handler *handler;
                     98:        int rc;
                     99: 
                    100:        /* Sanity check */
                    101:        if ( len < sizeof ( *frame ) )
                    102:                return NULL;
                    103: 
                    104:        /* Try each handler in turn */
                    105:        for_each_table_entry ( handler, FC_ELS_HANDLERS ) {
                    106:                if ( ( rc = handler->detect ( els, data, len ) ) == 0 )
                    107:                        return handler;
                    108:        }
                    109: 
                    110:        return NULL;
                    111: }
                    112: 
                    113: /**
                    114:  * Transmit Fibre Channel ELS frame
                    115:  *
                    116:  * @v els              Fibre Channel ELS transaction
                    117:  * @v data             Data to transmit
                    118:  * @v len              Length of data
                    119:  * @ret rc             Return status code
                    120:  */
                    121: int fc_els_tx ( struct fc_els *els, const void *data, size_t len ) {
                    122:        struct xfer_metadata meta;
                    123:        struct sockaddr_fc dest;
                    124:        int rc;
                    125: 
                    126:        DBGC2 ( els, FCELS_FMT " transmitting:\n", FCELS_ARGS ( els ) );
                    127:        DBGC2_HDA ( els, 0, data, len );
                    128: 
                    129:        /* Construct metadata */
                    130:        memset ( &meta, 0, sizeof ( meta ) );
                    131:        meta.flags = ( fc_els_is_request ( els ) ?
                    132:                       XFER_FL_OVER : ( XFER_FL_RESPONSE | XFER_FL_OUT ) );
                    133:        meta.dest = fc_fill_sockaddr ( &dest, &els->peer_port_id );
                    134: 
                    135:        /* Transmit frame */
                    136:        if ( ( rc = xfer_deliver_raw_meta ( &els->xchg, data, len,
                    137:                                            &meta ) ) != 0 ) {
                    138:                DBGC ( els, FCELS_FMT " could not deliver frame: %s\n",
                    139:                       FCELS_ARGS ( els ), strerror ( rc ) );
                    140:                return rc;
                    141:        }
                    142: 
                    143:        return 0;
                    144: }
                    145: 
                    146: /**
                    147:  * Receive Fibre Channel ELS frame
                    148:  *
                    149:  * @v els              Fibre Channel ELS transaction
                    150:  * @v iobuf            I/O buffer
                    151:  * @v meta             Data transfer metadata
                    152:  * @ret rc             Return status code
                    153:  */
                    154: static int fc_els_rx ( struct fc_els *els,
                    155:                       struct io_buffer *iobuf,
                    156:                       struct xfer_metadata *meta ) {
                    157:        struct fc_els_frame_common *frame = iobuf->data;
                    158:        struct sockaddr_fc *src = ( ( struct sockaddr_fc * ) meta->src );
                    159:        struct sockaddr_fc *dest = ( ( struct sockaddr_fc * ) meta->dest );
                    160:        size_t len = iob_len ( iobuf );
                    161:        int rc;
                    162: 
                    163:        /* Sanity check */
                    164:        if ( len < sizeof ( *frame ) ) {
                    165:                DBGC ( els, FCELS_FMT " received underlength frame:\n",
                    166:                       FCELS_ARGS ( els ) );
                    167:                DBGC_HDA ( els, 0, frame, len );
                    168:                rc = -EINVAL;
                    169:                goto done;
                    170:        }
                    171:        if ( ! src ) {
                    172:                DBGC ( els, FCELS_FMT " received frame missing source "
                    173:                       "address:\n", FCELS_ARGS ( els ) );
                    174:                rc = -EINVAL;
                    175:                goto done;
                    176:        }
                    177:        if ( ! dest ) {
                    178:                DBGC ( els, FCELS_FMT " received frame missing destination "
                    179:                       "address:\n", FCELS_ARGS ( els ) );
                    180:                rc = -EINVAL;
                    181:                goto done;
                    182:        }
                    183: 
                    184:        /* Check for rejection responses */
                    185:        if ( fc_els_is_request ( els ) &&
                    186:             ( frame->command != FC_ELS_LS_ACC ) ) {
                    187:                DBGC ( els, FCELS_FMT " rejected:\n", FCELS_ARGS ( els ) );
                    188:                DBGC_HDA ( els, 0, frame, len );
                    189:                rc = -EACCES;
                    190:                goto done;
                    191:        }
                    192: 
                    193:        /* Update port IDs */
                    194:        memcpy ( &els->port_id, &dest->sfc_port_id, sizeof ( els->port_id ) );
                    195:        memcpy ( &els->peer_port_id, &src->sfc_port_id,
                    196:                 sizeof ( els->peer_port_id ) );
                    197: 
                    198:        /* Determine handler, if necessary */
                    199:        if ( ! els->handler )
                    200:                els->handler = fc_els_detect ( els, frame, len );
                    201:        if ( ! els->handler )
                    202:                els->handler = &fc_els_unknown_handler;
                    203: 
                    204:        DBGC2 ( els, FCELS_FMT " received:\n", FCELS_ARGS ( els ) );
                    205:        DBGC2_HDA ( els, 0, frame, len );
                    206: 
                    207:        /* Handle received frame */
                    208:        if ( ( rc = els->handler->rx ( els, frame, len ) ) != 0 ) {
                    209:                DBGC ( els, FCELS_FMT " could not handle received frame: "
                    210:                       "%s\n", FCELS_ARGS ( els ), strerror ( rc ) );
                    211:                DBGC_HDA ( els, 0, frame, len );
                    212:                goto done;
                    213:        }
                    214: 
                    215:  done:
                    216:        /* Free I/O buffer */
                    217:        free_iob ( iobuf );
                    218: 
                    219:        /* Close transaction */
                    220:        fc_els_close ( els, rc );
                    221: 
                    222:        return rc;
                    223: }
                    224: 
                    225: /** Fibre Channel ELS exchange interface operations */
                    226: static struct interface_operation fc_els_xchg_op[] = {
                    227:        INTF_OP ( xfer_deliver, struct fc_els *, fc_els_rx ),
                    228:        INTF_OP ( intf_close, struct fc_els *, fc_els_close ),
                    229: };
                    230: 
                    231: /** Fibre Channel ELS exchange interface descriptor */
                    232: static struct interface_descriptor fc_els_xchg_desc =
                    233:        INTF_DESC ( struct fc_els, xchg, fc_els_xchg_op );
                    234: 
                    235: /** Fibre Channel ELS job control interface operations */
                    236: static struct interface_operation fc_els_job_op[] = {
                    237:        INTF_OP ( intf_close, struct fc_els *, fc_els_close ),
                    238: };
                    239: 
                    240: /** Fibre Channel ELS job control interface descriptor */
                    241: static struct interface_descriptor fc_els_job_desc =
                    242:        INTF_DESC ( struct fc_els, job, fc_els_job_op );
                    243: 
                    244: /**
                    245:  * Fibre Channel ELS process
                    246:  *
                    247:  * @v process          Process
                    248:  */
                    249: static void fc_els_step ( struct process *process ) {
                    250:        struct fc_els *els =
                    251:                container_of ( process, struct fc_els, process );
                    252:        int xchg_id;
                    253:        int rc;
                    254: 
                    255:        /* Sanity check */
                    256:        assert ( fc_els_is_request ( els ) );
                    257: 
                    258:        /* Stop process */
                    259:        process_del ( &els->process );
                    260: 
                    261:        /* Create exchange */
                    262:        if ( ( xchg_id = fc_xchg_originate ( &els->xchg, els->port,
                    263:                                             &els->peer_port_id,
                    264:                                             FC_TYPE_ELS ) ) < 0 ) {
                    265:                rc = xchg_id;
                    266:                DBGC ( els, FCELS_FMT " could not create exchange: %s\n",
                    267:                       FCELS_ARGS ( els ), strerror ( rc ) );
                    268:                fc_els_close ( els, rc );
                    269:                return;
                    270:        }
                    271: 
                    272:        /* Transmit request */
                    273:        if ( ( rc = els->handler->tx ( els ) ) != 0 ) {
                    274:                DBGC ( els, FCELS_FMT " could not transmit request: %s\n",
                    275:                       FCELS_ARGS ( els ), strerror ( rc ) );
                    276:                fc_els_close ( els, rc );
                    277:                return;
                    278:        }
                    279: }
                    280: 
                    281: /**
                    282:  * Create ELS transaction
                    283:  *
                    284:  * @v port             Fibre Channel port
                    285:  * @v port_id          Local port ID
                    286:  * @v peer_port_id     Peer port ID
                    287:  * @ret els            Fibre Channel ELS transaction, or NULL
                    288:  */
                    289: static struct fc_els * fc_els_create ( struct fc_port *port,
                    290:                                       struct fc_port_id *port_id,
                    291:                                       struct fc_port_id *peer_port_id ) {
                    292:        struct fc_els *els;
                    293: 
                    294:        /* Allocate and initialise structure */
                    295:        els = zalloc ( sizeof ( *els ) );
                    296:        if ( ! els )
                    297:                return NULL;
                    298:        ref_init ( &els->refcnt, fc_els_free );
                    299:        intf_init ( &els->job, &fc_els_job_desc, &els->refcnt );
                    300:        intf_init ( &els->xchg, &fc_els_xchg_desc, &els->refcnt );
                    301:        process_init_stopped ( &els->process, fc_els_step, &els->refcnt );
                    302:        els->port = fc_port_get ( port );
                    303:        memcpy ( &els->port_id, port_id, sizeof ( els->port_id ) );
                    304:        memcpy ( &els->peer_port_id, peer_port_id,
                    305:                 sizeof ( els->peer_port_id ) );
                    306:        return els;
                    307: }
                    308: 
                    309: /**
                    310:  * Create ELS request
                    311:  *
                    312:  * @v job              Parent job-control interface
                    313:  * @v port             Fibre Channel port
                    314:  * @v peer_port_id     Peer port ID
                    315:  * @v handler          ELS handler
                    316:  * @ret rc             Return status code
                    317:  */
                    318: int fc_els_request ( struct interface *job, struct fc_port *port,
                    319:                     struct fc_port_id *peer_port_id,
                    320:                     struct fc_els_handler *handler ) {
                    321:        struct fc_els *els;
                    322: 
                    323:        /* Allocate and initialise structure */
                    324:        els = fc_els_create ( port, &port->port_id, peer_port_id );
                    325:        if ( ! els )
                    326:                return -ENOMEM;
                    327:        els->handler = handler;
                    328:        els->flags = FC_ELS_REQUEST;
                    329:        process_add ( &els->process );
                    330: 
                    331:        /* Attach to parent job interface, mortalise self, and return */
                    332:        intf_plug_plug ( &els->job, job );
                    333:        ref_put ( &els->refcnt );
                    334:        return 0;
                    335: }
                    336: 
                    337: /**
                    338:  * Create ELS response
                    339:  *
                    340:  * @v xchg             Exchange interface
                    341:  * @v port             Fibre Channel port
                    342:  * @v port_id          Local port ID
                    343:  * @v peer_port_id     Peer port ID
                    344:  * @ret rc             Return status code
                    345:  */
                    346: static int fc_els_respond ( struct interface *xchg, struct fc_port *port,
                    347:                            struct fc_port_id *port_id,
                    348:                            struct fc_port_id *peer_port_id ) {
                    349:        struct fc_els *els;
                    350: 
                    351:        /* Allocate and initialise structure */
                    352:        els = fc_els_create ( port, port_id, peer_port_id );
                    353:        if ( ! els )
                    354:                return -ENOMEM;
                    355: 
                    356:        /* Attach to exchange interface, mortalise self, and return */
                    357:        intf_plug_plug ( &els->xchg, xchg );
                    358:        ref_put ( &els->refcnt );
                    359:        return 0;
                    360: }
                    361: 
                    362: /** Fibre Channel ELS responder */
                    363: struct fc_responder fc_els_responder __fc_responder = {
                    364:        .type = FC_TYPE_ELS,
                    365:        .respond = fc_els_respond,
                    366: };
                    367: 
                    368: /******************************************************************************
                    369:  *
                    370:  * Unknown ELS handler
                    371:  *
                    372:  ******************************************************************************
                    373:  */
                    374: 
                    375: /**
                    376:  * Transmit unknown ELS request
                    377:  *
                    378:  * @v els              Fibre Channel ELS transaction
                    379:  * @ret rc             Return status code
                    380:  */
                    381: static int fc_els_unknown_tx ( struct fc_els *els __unused ) {
                    382:        return -ENOTSUP;
                    383: }
                    384: 
                    385: /**
                    386:  * Transmit unknown ELS response
                    387:  *
                    388:  * @v els              Fibre Channel ELS transaction
                    389:  * @ret rc             Return status code
                    390:  */
                    391: static int fc_els_unknown_tx_response ( struct fc_els *els ) {
                    392:        struct fc_ls_rjt_frame ls_rjt;
                    393: 
                    394:        /* Construct LS_RJT */
                    395:        memset ( &ls_rjt, 0, sizeof ( ls_rjt ) );
                    396:        ls_rjt.command = FC_ELS_LS_RJT;
                    397:        ls_rjt.reason = FC_ELS_RJT_UNSUPPORTED;
                    398: 
                    399:        /* Transmit LS_RJT */
                    400:        return fc_els_tx ( els, &ls_rjt, sizeof ( ls_rjt ) );
                    401: }
                    402: 
                    403: /**
                    404:  * Receive unknown ELS
                    405:  *
                    406:  * @v els              Fibre Channel ELS transaction
                    407:  * @v data             ELS frame
                    408:  * @v len              Length of ELS frame
                    409:  * @ret rc             Return status code
                    410:  */
                    411: static int fc_els_unknown_rx ( struct fc_els *els, void *data, size_t len ) {
                    412:        int rc;
                    413: 
                    414:        DBGC ( els, FCELS_FMT ":\n", FCELS_ARGS ( els ) );
                    415:        DBGC_HDA ( els, 0, data, len );
                    416: 
                    417:        /* Transmit response, if applicable */
                    418:        if ( ! fc_els_is_request ( els ) ) {
                    419:                if ( ( rc = fc_els_unknown_tx_response ( els ) ) != 0 )
                    420:                        return rc;
                    421:        }
                    422: 
                    423:        return 0;
                    424: }
                    425: 
                    426: /**
                    427:  * Detect unknown ELS
                    428:  *
                    429:  * @v els              Fibre Channel ELS transaction
                    430:  * @v data             ELS frame
                    431:  * @v len              Length of ELS frame
                    432:  * @ret rc             Return status code
                    433:  */
                    434: static int fc_els_unknown_detect ( struct fc_els *els __unused,
                    435:                                   const void *data __unused,
                    436:                                   size_t len __unused ) {
                    437:        return -ENOTSUP;
                    438: }
                    439: 
                    440: /** Unknown ELS handler */
                    441: struct fc_els_handler fc_els_unknown_handler __fc_els_handler = {
                    442:        .name           = "UNKNOWN",
                    443:        .tx             = fc_els_unknown_tx,
                    444:        .rx             = fc_els_unknown_rx,
                    445:        .detect         = fc_els_unknown_detect,
                    446: };
                    447: 
                    448: /******************************************************************************
                    449:  *
                    450:  * FLOGI
                    451:  *
                    452:  ******************************************************************************
                    453:  */
                    454: 
                    455: /**
                    456:  * Transmit FLOGI
                    457:  *
                    458:  * @v els              Fibre Channel ELS transaction
                    459:  * @ret rc             Return status code
                    460:  */
                    461: static int fc_els_flogi_tx ( struct fc_els *els ) {
                    462:        struct fc_login_frame flogi;
                    463: 
                    464:        /* Construct FLOGI */
                    465:        memset ( &flogi, 0, sizeof ( flogi ) );
                    466:        flogi.command = fc_els_tx_command ( els, FC_ELS_FLOGI );
                    467:        flogi.common.version = htons ( FC_LOGIN_VERSION );
                    468:        flogi.common.credit = htons ( FC_LOGIN_DEFAULT_B2B );
                    469:        flogi.common.flags = htons ( FC_LOGIN_CONTINUOUS_OFFSET );
                    470:        flogi.common.mtu = htons ( FC_LOGIN_DEFAULT_MTU );
                    471:        memcpy ( &flogi.port_wwn, &els->port->port_wwn,
                    472:                 sizeof ( flogi.port_wwn ) );
                    473:        memcpy ( &flogi.node_wwn, &els->port->node_wwn,
                    474:                 sizeof ( flogi.node_wwn ) );
                    475:        flogi.class3.flags = htons ( FC_LOGIN_CLASS_VALID |
                    476:                                     FC_LOGIN_CLASS_SEQUENTIAL );
                    477: 
                    478:        /* Transmit FLOGI */
                    479:        return fc_els_tx ( els, &flogi, sizeof ( flogi ) );
                    480: }
                    481: 
                    482: /**
                    483:  * Receive FLOGI
                    484:  *
                    485:  * @v els              Fibre Channel ELS transaction
                    486:  * @v data             ELS frame
                    487:  * @v len              Length of ELS frame
                    488:  * @ret rc             Return status code
                    489:  */
                    490: static int fc_els_flogi_rx ( struct fc_els *els, void *data, size_t len ) {
                    491:        struct fc_login_frame *flogi = data;
                    492:        int has_fabric;
                    493:        int rc;
                    494: 
                    495:        /* Sanity check */
                    496:        if ( len < sizeof ( *flogi ) ) {
                    497:                DBGC ( els, FCELS_FMT " received underlength frame:\n",
                    498:                       FCELS_ARGS ( els ) );
                    499:                DBGC_HDA ( els, 0, data, len );
                    500:                return -EINVAL;
                    501:        }
                    502: 
                    503:        /* Extract parameters */
                    504:        has_fabric = ( flogi->common.flags & htons ( FC_LOGIN_F_PORT ) );
                    505:        DBGC ( els, FCELS_FMT " has node %s\n", FCELS_ARGS ( els ),
                    506:               fc_ntoa ( &flogi->node_wwn ) );
                    507:        DBGC ( els, FCELS_FMT " has port %s\n", FCELS_ARGS ( els ),
                    508:               fc_ntoa ( &flogi->port_wwn ) );
                    509:        if ( has_fabric ) {
                    510:                DBGC ( els, FCELS_FMT " has fabric with", FCELS_ARGS ( els ) );
                    511:                DBGC ( els, " local ID %s\n", fc_id_ntoa ( &els->port_id ) );
                    512:        } else {
                    513:                DBGC ( els, FCELS_FMT " has point-to-point link\n",
                    514:                       FCELS_ARGS ( els ) );
                    515:        }
                    516: 
                    517:        /* Log in port */
                    518:        if ( ( rc = fc_port_login ( els->port, &els->port_id, &flogi->node_wwn,
                    519:                                    &flogi->port_wwn, has_fabric ) ) != 0 ) {
                    520:                DBGC ( els, FCELS_FMT " could not log in port: %s\n",
                    521:                       FCELS_ARGS ( els ), strerror ( rc ) );
                    522:                return rc;
                    523:        }
                    524: 
                    525:        /* Send any responses to the newly-assigned peer port ID, if
                    526:         * applicable.
                    527:         */
                    528:        if ( ! has_fabric ) {
                    529:                memcpy ( &els->peer_port_id, &els->port->ptp_link_port_id,
                    530:                         sizeof ( els->peer_port_id ) );
                    531:        }
                    532: 
                    533:        /* Transmit response, if applicable */
                    534:        if ( ! fc_els_is_request ( els ) ) {
                    535:                if ( ( rc = fc_els_flogi_tx ( els ) ) != 0 )
                    536:                        return rc;
                    537:        }
                    538: 
                    539:        return 0;
                    540: }
                    541: 
                    542: /**
                    543:  * Detect FLOGI
                    544:  *
                    545:  * @v els              Fibre Channel ELS transaction
                    546:  * @v data             ELS frame
                    547:  * @v len              Length of ELS frame
                    548:  * @ret rc             Return status code
                    549:  */
                    550: static int fc_els_flogi_detect ( struct fc_els *els __unused, const void *data,
                    551:                                 size_t len __unused ) {
                    552:        const struct fc_login_frame *flogi = data;
                    553: 
                    554:        /* Check for FLOGI */
                    555:        if ( flogi->command != FC_ELS_FLOGI )
                    556:                return -EINVAL;
                    557: 
                    558:        return 0;
                    559: }
                    560: 
                    561: /** FLOGI ELS handler */
                    562: struct fc_els_handler fc_els_flogi_handler __fc_els_handler = {
                    563:        .name           = "FLOGI",
                    564:        .tx             = fc_els_flogi_tx,
                    565:        .rx             = fc_els_flogi_rx,
                    566:        .detect         = fc_els_flogi_detect,
                    567: };
                    568: 
                    569: /**
                    570:  * Create FLOGI request
                    571:  *
                    572:  * @v parent           Parent interface
                    573:  * @v port             Fibre Channel port
                    574:  * @ret rc             Return status code
                    575:  */
                    576: int fc_els_flogi ( struct interface *parent, struct fc_port *port ) {
                    577: 
                    578:        return fc_els_request ( parent, port, &fc_f_port_id,
                    579:                                &fc_els_flogi_handler );
                    580: }
                    581: 
                    582: /******************************************************************************
                    583:  *
                    584:  * PLOGI
                    585:  *
                    586:  ******************************************************************************
                    587:  */
                    588: 
                    589: /**
                    590:  * Transmit PLOGI
                    591:  *
                    592:  * @v els              Fibre Channel ELS transaction
                    593:  * @ret rc             Return status code
                    594:  */
                    595: static int fc_els_plogi_tx ( struct fc_els *els ) {
                    596:        struct fc_login_frame plogi;
                    597: 
                    598:        /* Construct PLOGI */
                    599:        memset ( &plogi, 0, sizeof ( plogi ) );
                    600:        plogi.command = fc_els_tx_command ( els, FC_ELS_PLOGI );
                    601:        plogi.common.version = htons ( FC_LOGIN_VERSION );
                    602:        plogi.common.credit = htons ( FC_LOGIN_DEFAULT_B2B );
                    603:        plogi.common.flags = htons ( FC_LOGIN_CONTINUOUS_OFFSET );
                    604:        plogi.common.mtu = htons ( FC_LOGIN_DEFAULT_MTU );
                    605:        plogi.common.u.plogi.max_seq = htons ( FC_LOGIN_DEFAULT_MAX_SEQ );
                    606:        plogi.common.u.plogi.rel_offs = htons ( FC_LOGIN_DEFAULT_REL_OFFS );
                    607:        plogi.common.e_d_tov = htonl ( FC_LOGIN_DEFAULT_E_D_TOV );
                    608:        memcpy ( &plogi.port_wwn, &els->port->port_wwn,
                    609:                 sizeof ( plogi.port_wwn ) );
                    610:        memcpy ( &plogi.node_wwn, &els->port->node_wwn,
                    611:                 sizeof ( plogi.node_wwn ) );
                    612:        plogi.class3.flags = htons ( FC_LOGIN_CLASS_VALID |
                    613:                                     FC_LOGIN_CLASS_SEQUENTIAL );
                    614:        plogi.class3.mtu = htons ( FC_LOGIN_DEFAULT_MTU );
                    615:        plogi.class3.max_seq = htons ( FC_LOGIN_DEFAULT_MAX_SEQ );
                    616:        plogi.class3.max_seq_per_xchg = 1;
                    617: 
                    618:        /* Transmit PLOGI */
                    619:        return fc_els_tx ( els, &plogi, sizeof ( plogi ) );
                    620: }
                    621: 
                    622: /**
                    623:  * Receive PLOGI
                    624:  *
                    625:  * @v els              Fibre Channel ELS transaction
                    626:  * @v data             ELS frame
                    627:  * @v len              Length of ELS frame
                    628:  * @ret rc             Return status code
                    629:  */
                    630: static int fc_els_plogi_rx ( struct fc_els *els, void *data, size_t len ) {
                    631:        struct fc_login_frame *plogi = data;
                    632:        struct fc_peer *peer;
                    633:        int rc;
                    634: 
                    635:        /* Sanity checks */
                    636:        if ( len < sizeof ( *plogi ) ) {
                    637:                DBGC ( els, FCELS_FMT " received underlength frame:\n",
                    638:                       FCELS_ARGS ( els ) );
                    639:                DBGC_HDA ( els, 0, data, len );
                    640:                rc = -EINVAL;
                    641:                goto err_sanity;
                    642:        }
                    643:        if ( ! fc_link_ok ( &els->port->link ) ) {
                    644:                DBGC ( els, FCELS_FMT " received while port link is down\n",
                    645:                       FCELS_ARGS ( els ) );
                    646:                rc = -EINVAL;
                    647:                goto err_sanity;
                    648:        }
                    649: 
                    650:        /* Extract parameters */
                    651:        DBGC ( els, FCELS_FMT " has node %s\n", FCELS_ARGS ( els ),
                    652:               fc_ntoa ( &plogi->node_wwn ) );
                    653:        DBGC ( els, FCELS_FMT " has port %s as %s\n",
                    654:               FCELS_ARGS ( els ), fc_ntoa ( &plogi->port_wwn ),
                    655:               fc_id_ntoa ( &els->peer_port_id ) );
                    656: 
                    657:        /* Get peer */
                    658:        peer = fc_peer_get_wwn ( &plogi->port_wwn );
                    659:        if ( ! peer ) {
                    660:                DBGC ( els, FCELS_FMT " could not create peer\n",
                    661:                       FCELS_ARGS ( els ) );
                    662:                rc = -ENOMEM;
                    663:                goto err_peer_get_wwn;
                    664:        }
                    665: 
                    666:        /* Record login */
                    667:        if ( ( rc = fc_peer_login ( peer, els->port,
                    668:                                    &els->peer_port_id ) ) != 0 ) {
                    669:                DBGC ( els, FCELS_FMT " could not log in peer: %s\n",
                    670:                       FCELS_ARGS ( els ), strerror ( rc ) );
                    671:                goto err_login;
                    672:        }
                    673: 
                    674:        /* Transmit response, if applicable */
                    675:        if ( ! fc_els_is_request ( els ) ) {
                    676:                if ( ( rc = fc_els_plogi_tx ( els ) ) != 0 )
                    677:                        goto err_plogi_tx;
                    678:        }
                    679: 
                    680:        /* Drop temporary reference to peer */
                    681:        fc_peer_put ( peer );
                    682: 
                    683:        return 0;
                    684: 
                    685:  err_plogi_tx:
                    686:  err_login:
                    687:        fc_peer_put ( peer );
                    688:  err_peer_get_wwn:
                    689:  err_sanity:
                    690:        return rc;
                    691: }
                    692: 
                    693: /**
                    694:  * Detect PLOGI
                    695:  *
                    696:  * @v els              Fibre Channel ELS transaction
                    697:  * @v data             ELS frame
                    698:  * @v len              Length of ELS frame
                    699:  * @ret rc             Return status code
                    700:  */
                    701: static int fc_els_plogi_detect ( struct fc_els *els __unused, const void *data,
                    702:                                 size_t len __unused ) {
                    703:        const struct fc_login_frame *plogi = data;
                    704: 
                    705:        /* Check for PLOGI */
                    706:        if ( plogi->command != FC_ELS_PLOGI )
                    707:                return -EINVAL;
                    708: 
                    709:        return 0;
                    710: }
                    711: 
                    712: /** PLOGI ELS handler */
                    713: struct fc_els_handler fc_els_plogi_handler __fc_els_handler = {
                    714:        .name           = "PLOGI",
                    715:        .tx             = fc_els_plogi_tx,
                    716:        .rx             = fc_els_plogi_rx,
                    717:        .detect         = fc_els_plogi_detect,
                    718: };
                    719: 
                    720: /**
                    721:  * Create PLOGI request
                    722:  *
                    723:  * @v parent           Parent interface
                    724:  * @v port             Fibre Channel port
                    725:  * @v peer_port_id     Peer port ID
                    726:  * @ret rc             Return status code
                    727:  */
                    728: int fc_els_plogi ( struct interface *parent, struct fc_port *port,
                    729:                   struct fc_port_id *peer_port_id ) {
                    730: 
                    731:        return fc_els_request ( parent, port, peer_port_id,
                    732:                                &fc_els_plogi_handler );
                    733: }
                    734: 
                    735: /******************************************************************************
                    736:  *
                    737:  * LOGO
                    738:  *
                    739:  ******************************************************************************
                    740:  */
                    741: 
                    742: /**
                    743:  * Transmit LOGO request
                    744:  *
                    745:  * @v els              Fibre Channel ELS transaction
                    746:  * @ret rc             Return status code
                    747:  */
                    748: static int fc_els_logo_tx ( struct fc_els *els ) {
                    749:        struct fc_logout_request_frame logo;
                    750: 
                    751:        /* Construct LOGO */
                    752:        memset ( &logo, 0, sizeof ( logo ) );
                    753:        logo.command = FC_ELS_LOGO;
                    754:        memcpy ( &logo.port_id, &els->port->port_id, sizeof ( logo.port_id ) );
                    755:        memcpy ( &logo.port_wwn, &els->port->port_wwn,
                    756:                 sizeof ( logo.port_wwn ) );
                    757: 
                    758:        /* Transmit LOGO */
                    759:        return fc_els_tx ( els, &logo, sizeof ( logo ) );
                    760: }
                    761: 
                    762: /**
                    763:  * Transmit LOGO response
                    764:  *
                    765:  * @v els              Fibre Channel ELS transaction
                    766:  * @ret rc             Return status code
                    767:  */
                    768: static int fc_els_logo_tx_response ( struct fc_els *els ) {
                    769:        struct fc_logout_response_frame logo;
                    770: 
                    771:        /* Construct LOGO */
                    772:        memset ( &logo, 0, sizeof ( logo ) );
                    773:        logo.command = FC_ELS_LS_ACC;
                    774: 
                    775:        /* Transmit LOGO */
                    776:        return fc_els_tx ( els, &logo, sizeof ( logo ) );
                    777: }
                    778: 
                    779: /**
                    780:  * Log out individual peer or whole port as applicable
                    781:  *
                    782:  * @v els              Fibre Channel ELS transaction
                    783:  * @v port_id          Peer port ID
                    784:  */
                    785: static void fc_els_logo_logout ( struct fc_els *els,
                    786:                                 struct fc_port_id *peer_port_id ) {
                    787:        struct fc_peer *peer;
                    788: 
                    789:        if ( ( memcmp ( peer_port_id, &fc_f_port_id,
                    790:                        sizeof ( *peer_port_id ) ) == 0 ) ||
                    791:             ( memcmp ( peer_port_id, &els->port->port_id,
                    792:                        sizeof ( *peer_port_id ) ) == 0 ) ) {
                    793:                fc_port_logout ( els->port, 0 );
                    794:        } else {
                    795:                peer = fc_peer_get_port_id ( els->port, peer_port_id );
                    796:                if ( peer ) {
                    797:                        fc_peer_logout ( peer, 0 );
                    798:                        fc_peer_put ( peer );
                    799:                }
                    800:        }
                    801: }
                    802: 
                    803: /**
                    804:  * Receive LOGO request
                    805:  *
                    806:  * @v els              Fibre Channel ELS transaction
                    807:  * @v data             ELS frame
                    808:  * @v len              Length of ELS frame
                    809:  * @ret rc             Return status code
                    810:  */
                    811: static int fc_els_logo_rx_request ( struct fc_els *els, void *data,
                    812:                                    size_t len ) {
                    813:        struct fc_logout_request_frame *logo = data;
                    814:        int rc;
                    815: 
                    816:        /* Sanity check */
                    817:        if ( len < sizeof ( *logo ) ) {
                    818:                DBGC ( els, FCELS_FMT " received underlength frame:\n",
                    819:                       FCELS_ARGS ( els ) );
                    820:                DBGC_HDA ( els, 0, data, len );
                    821:                return -EINVAL;
                    822:        }
                    823: 
                    824:        DBGC ( els, FCELS_FMT " has port %s as %s\n", FCELS_ARGS ( els ),
                    825:               fc_ntoa ( &logo->port_wwn ), fc_id_ntoa ( &logo->port_id ) );
                    826: 
                    827:        /* Log out individual peer or whole port as applicable */
                    828:        fc_els_logo_logout ( els, &logo->port_id );
                    829: 
                    830:        /* Transmit repsonse */
                    831:        if ( ( rc = fc_els_logo_tx_response ( els ) ) != 0 )
                    832:                return rc;
                    833: 
                    834:        return 0;
                    835: }
                    836: 
                    837: /**
                    838:  * Receive LOGO response
                    839:  *
                    840:  * @v els              Fibre Channel ELS transaction
                    841:  * @v data             ELS frame
                    842:  * @v len              Length of ELS frame
                    843:  * @ret rc             Return status code
                    844:  */
                    845: static int fc_els_logo_rx_response ( struct fc_els *els, void *data __unused,
                    846:                                     size_t len __unused ) {
                    847: 
                    848:        /* Log out individual peer or whole port as applicable */
                    849:        fc_els_logo_logout ( els, &els->peer_port_id );
                    850: 
                    851:        return 0;
                    852: }
                    853: 
                    854: /**
                    855:  * Receive LOGO
                    856:  *
                    857:  * @v els              Fibre Channel ELS transaction
                    858:  * @v data             ELS frame
                    859:  * @v len              Length of ELS frame
                    860:  * @ret rc             Return status code
                    861:  */
                    862: static int fc_els_logo_rx ( struct fc_els *els, void *data, size_t len ) {
                    863: 
                    864:        if ( fc_els_is_request ( els ) ) {
                    865:                return fc_els_logo_rx_response ( els, data, len );
                    866:        } else {
                    867:                return fc_els_logo_rx_request ( els, data, len );
                    868:        }
                    869: }
                    870: 
                    871: /**
                    872:  * Detect LOGO
                    873:  *
                    874:  * @v els              Fibre Channel ELS transaction
                    875:  * @v data             ELS frame
                    876:  * @v len              Length of ELS frame
                    877:  * @ret rc             Return status code
                    878:  */
                    879: static int fc_els_logo_detect ( struct fc_els *els __unused, const void *data,
                    880:                                size_t len __unused ) {
                    881:        const struct fc_logout_request_frame *logo = data;
                    882: 
                    883:        /* Check for LOGO */
                    884:        if ( logo->command != FC_ELS_LOGO )
                    885:                return -EINVAL;
                    886: 
                    887:        return 0;
                    888: }
                    889: 
                    890: /** LOGO ELS handler */
                    891: struct fc_els_handler fc_els_logo_handler __fc_els_handler = {
                    892:        .name           = "LOGO",
                    893:        .tx             = fc_els_logo_tx,
                    894:        .rx             = fc_els_logo_rx,
                    895:        .detect         = fc_els_logo_detect,
                    896: };
                    897: 
                    898: /**
                    899:  * Create LOGO request
                    900:  *
                    901:  * @v parent           Parent interface
                    902:  * @v port             Fibre Channel port
                    903:  * @v peer_port_id     Peer port ID
                    904:  * @ret rc             Return status code
                    905:  */
                    906: int fc_els_logo ( struct interface *parent, struct fc_port *port,
                    907:                  struct fc_port_id *peer_port_id ) {
                    908: 
                    909:        return fc_els_request ( parent, port, peer_port_id,
                    910:                                &fc_els_logo_handler );
                    911: }
                    912: 
                    913: /******************************************************************************
                    914:  *
                    915:  * PRLI
                    916:  *
                    917:  ******************************************************************************
                    918:  */
                    919: 
                    920: /**
                    921:  * Find PRLI descriptor
                    922:  *
                    923:  * @v type             Upper-layer protocol type
                    924:  * @ret descriptor     PRLI descriptor, or NULL
                    925:  */
                    926: static struct fc_els_prli_descriptor *
                    927: fc_els_prli_descriptor ( unsigned int type ) {
                    928:        struct fc_els_prli_descriptor *descriptor;
                    929: 
                    930:        for_each_table_entry ( descriptor, FC_ELS_PRLI_DESCRIPTORS ) {
                    931:                if ( descriptor->type == type )
                    932:                        return descriptor;
                    933:        }
                    934:        return NULL;
                    935: }
                    936: 
                    937: /**
                    938:  * Transmit PRLI
                    939:  *
                    940:  * @v els              Fibre Channel ELS transaction
                    941:  * @v descriptor       ELS PRLI descriptor
                    942:  * @v param            Service parameters
                    943:  * @ret rc             Return status code
                    944:  */
                    945: int fc_els_prli_tx ( struct fc_els *els,
                    946:                     struct fc_els_prli_descriptor *descriptor, void *param ) {
                    947:        struct {
                    948:                struct fc_prli_frame frame;
                    949:                uint8_t param[descriptor->param_len];
                    950:        } __attribute__ (( packed )) prli;
                    951:        struct fc_ulp *ulp;
                    952:        int rc;
                    953: 
                    954:        /* Get ULP */
                    955:        ulp = fc_ulp_get_port_id_type ( els->port, &els->peer_port_id,
                    956:                                        descriptor->type );
                    957:        if ( ! ulp ) {
                    958:                rc = -ENOMEM;
                    959:                goto err_get_port_id_type;
                    960:        }
                    961: 
                    962:        /* Build frame for transmission */
                    963:        memset ( &prli, 0, sizeof ( prli ) );
                    964:        prli.frame.command = fc_els_tx_command ( els, FC_ELS_PRLI );
                    965:        prli.frame.page_len =
                    966:                ( sizeof ( prli.frame.page ) + sizeof ( prli.param ) );
                    967:        prli.frame.len = htons ( sizeof ( prli ) );
                    968:        prli.frame.page.type = descriptor->type;
                    969:        if ( fc_els_is_request ( els ) ) {
                    970:                prli.frame.page.flags |= htons ( FC_PRLI_ESTABLISH );
                    971:        } else if ( fc_link_ok ( &ulp->link ) ) {
                    972:                prli.frame.page.flags |= htons ( FC_PRLI_ESTABLISH |
                    973:                                                    FC_PRLI_RESPONSE_SUCCESS );
                    974:        }
                    975:        memcpy ( &prli.param, param, sizeof ( prli.param ) );
                    976: 
                    977:        /* Transmit frame */
                    978:        if ( ( rc = fc_els_tx ( els, &prli, sizeof ( prli ) ) ) != 0 )
                    979:                goto err_tx;
                    980: 
                    981:        /* Drop temporary reference to ULP */
                    982:        fc_ulp_put ( ulp );
                    983: 
                    984:        return 0;
                    985: 
                    986:  err_tx:
                    987:        fc_ulp_put ( ulp );
                    988:  err_get_port_id_type:
                    989:        return rc;
                    990: }
                    991: 
                    992: /**
                    993:  * Receive PRLI
                    994:  *
                    995:  * @v els              Fibre Channel ELS transaction
                    996:  * @v descriptor       ELS PRLI descriptor
                    997:  * @v frame            ELS frame
                    998:  * @v len              Length of ELS frame
                    999:  * @ret rc             Return status code
                   1000:  */
                   1001: int fc_els_prli_rx ( struct fc_els *els,
                   1002:                     struct fc_els_prli_descriptor *descriptor,
                   1003:                     void *data, size_t len ) {
                   1004:        struct {
                   1005:                struct fc_prli_frame frame;
                   1006:                uint8_t param[descriptor->param_len];
                   1007:        } __attribute__ (( packed )) *prli = data;
                   1008:        struct fc_ulp *ulp;
                   1009:        int rc;
                   1010: 
                   1011:        /* Sanity check */
                   1012:        if ( len < sizeof ( *prli ) ) {
                   1013:                DBGC ( els, FCELS_FMT " received underlength frame:\n",
                   1014:                       FCELS_ARGS ( els ) );
                   1015:                DBGC_HDA ( els, 0, data, len );
                   1016:                rc = -EINVAL;
                   1017:                goto err_sanity;
                   1018:        }
                   1019: 
                   1020:        DBGC ( els, FCELS_FMT " has parameters:\n", FCELS_ARGS ( els ) );
                   1021:        DBGC_HDA ( els, 0, prli->param, sizeof ( prli->param ) );
                   1022: 
                   1023:        /* Get ULP */
                   1024:        ulp = fc_ulp_get_port_id_type ( els->port, &els->peer_port_id,
                   1025:                                        descriptor->type );
                   1026:        if ( ! ulp ) {
                   1027:                rc = -ENOMEM;
                   1028:                goto err_get_port_id_type;
                   1029:        }
                   1030: 
                   1031:        /* Sanity check */
                   1032:        if ( ! fc_link_ok ( &ulp->peer->link ) ) {
                   1033:                DBGC ( els, FCELS_FMT " received while peer link is down\n",
                   1034:                       FCELS_ARGS ( els ) );
                   1035:                rc = -EINVAL;
                   1036:                goto err_link;
                   1037:        }
                   1038: 
                   1039:        /* Log in ULP, if applicable */
                   1040:        if ( prli->frame.page.flags & htons ( FC_PRLI_ESTABLISH ) ) {
                   1041:                if ( ( rc = fc_ulp_login ( ulp, prli->param,
                   1042:                                           sizeof ( prli->param ),
                   1043:                                           fc_els_is_request ( els ) ) ) != 0 ){
                   1044:                        DBGC ( els, FCELS_FMT " could not log in ULP: %s\n",
                   1045:                               FCELS_ARGS ( els ), strerror ( rc ) );
                   1046:                        goto err_login;
                   1047:                }
                   1048:        } else {
                   1049:                if ( fc_els_is_request ( els ) ) {
                   1050:                        fc_ulp_logout ( ulp, -EACCES );
                   1051:                } else {
                   1052:                        /* This is just an information-gathering PRLI; do not
                   1053:                         * log in or out
                   1054:                         */
                   1055:                }
                   1056:        }
                   1057: 
                   1058:        /* Transmit response, if applicable */
                   1059:        if ( ! fc_els_is_request ( els ) ) {
                   1060:                if ( ( rc = els->handler->tx ( els ) ) != 0 )
                   1061:                        goto err_tx;
                   1062:        }
                   1063: 
                   1064:        /* Drop temporary reference to ULP */
                   1065:        fc_ulp_put ( ulp );
                   1066: 
                   1067:        return 0;
                   1068: 
                   1069:  err_tx:
                   1070:  err_login:
                   1071:  err_link:
                   1072:        fc_ulp_put ( ulp );
                   1073:  err_get_port_id_type:
                   1074:  err_sanity:
                   1075:        return rc;
                   1076: }
                   1077: 
                   1078: /**
                   1079:  * Detect PRLI
                   1080:  *
                   1081:  * @v els              Fibre Channel ELS transaction
                   1082:  * @v descriptor       ELS PRLI descriptor
                   1083:  * @v data             ELS frame
                   1084:  * @v len              Length of ELS frame
                   1085:  * @ret rc             Return status code
                   1086:  */
                   1087: int fc_els_prli_detect ( struct fc_els *els __unused,
                   1088:                         struct fc_els_prli_descriptor *descriptor,
                   1089:                         const void *data, size_t len ) {
                   1090:        const struct {
                   1091:                struct fc_prli_frame frame;
                   1092:                uint8_t param[descriptor->param_len];
                   1093:        } __attribute__ (( packed )) *prli = data;
                   1094: 
                   1095:        /* Check for PRLI */
                   1096:        if ( prli->frame.command != FC_ELS_PRLI )
                   1097:                return -EINVAL;
                   1098: 
                   1099:        /* Check for sufficient length to contain service parameter page */
                   1100:        if ( len < sizeof ( *prli ) )
                   1101:                return -EINVAL;
                   1102: 
                   1103:        /* Check for upper-layer protocol type */
                   1104:        if ( prli->frame.page.type != descriptor->type )
                   1105:                return -EINVAL;
                   1106: 
                   1107:        return 0;
                   1108: }
                   1109: 
                   1110: /**
                   1111:  * Create PRLI request
                   1112:  *
                   1113:  * @v parent           Parent interface
                   1114:  * @v port             Fibre Channel port
                   1115:  * @v peer_port_id     Peer port ID
                   1116:  * @v type             Upper-layer protocol type
                   1117:  * @ret rc             Return status code
                   1118:  */
                   1119: int fc_els_prli ( struct interface *parent, struct fc_port *port,
                   1120:                  struct fc_port_id *peer_port_id, unsigned int type ) {
                   1121:        struct fc_els_prli_descriptor *descriptor;
                   1122: 
                   1123:        /* Find a PRLI descriptor */
                   1124:        descriptor = fc_els_prli_descriptor ( type );
                   1125:        if ( ! descriptor )
                   1126:                return -ENOTSUP;
                   1127: 
                   1128:        return fc_els_request ( parent, port, peer_port_id,
                   1129:                                descriptor->handler );
                   1130: }
                   1131: 
                   1132: /******************************************************************************
                   1133:  *
                   1134:  * RTV
                   1135:  *
                   1136:  ******************************************************************************
                   1137:  */
                   1138: 
                   1139: /**
                   1140:  * Transmit RTV response
                   1141:  *
                   1142:  * @v els              Fibre Channel ELS transaction
                   1143:  * @ret rc             Return status code
                   1144:  */
                   1145: static int fc_els_rtv_tx_response ( struct fc_els *els ) {
                   1146:        struct fc_rtv_response_frame rtv;
                   1147: 
                   1148:        /* Construct RTV */
                   1149:        memset ( &rtv, 0, sizeof ( rtv ) );
                   1150:        rtv.command = FC_ELS_LS_ACC;
                   1151:        rtv.e_d_tov = htonl ( FC_LOGIN_DEFAULT_E_D_TOV );
                   1152: 
                   1153:        /* Transmit RTV */
                   1154:        return fc_els_tx ( els, &rtv, sizeof ( rtv ) );
                   1155: }
                   1156: 
                   1157: /**
                   1158:  * Receive RTV
                   1159:  *
                   1160:  * @v els              Fibre Channel ELS transaction
                   1161:  * @v data             ELS frame
                   1162:  * @v len              Length of ELS frame
                   1163:  * @ret rc             Return status code
                   1164:  */
                   1165: static int fc_els_rtv_rx ( struct fc_els *els, void *data __unused,
                   1166:                           size_t len __unused ) {
                   1167:        int rc;
                   1168: 
                   1169:        DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
                   1170: 
                   1171:        /* Transmit response */
                   1172:        if ( ! fc_els_is_request ( els ) ) {
                   1173:                if ( ( rc = fc_els_rtv_tx_response ( els ) ) != 0 )
                   1174:                        return rc;
                   1175:        }
                   1176: 
                   1177:        return 0;
                   1178: }
                   1179: 
                   1180: /**
                   1181:  * Detect RTV
                   1182:  *
                   1183:  * @v els              Fibre Channel ELS transaction
                   1184:  * @v data             ELS frame
                   1185:  * @v len              Length of ELS frame
                   1186:  * @ret rc             Return status code
                   1187:  */
                   1188: static int fc_els_rtv_detect ( struct fc_els *els __unused, const void *data,
                   1189:                               size_t len __unused ) {
                   1190:        const struct fc_rtv_request_frame *rtv = data;
                   1191: 
                   1192:        /* Check for RTV */
                   1193:        if ( rtv->command != FC_ELS_RTV )
                   1194:                return -EINVAL;
                   1195: 
                   1196:        return 0;
                   1197: }
                   1198: 
                   1199: /** RTV ELS handler */
                   1200: struct fc_els_handler fc_els_rtv_handler __fc_els_handler = {
                   1201:        .name           = "RTV",
                   1202:        .tx             = fc_els_unknown_tx,
                   1203:        .rx             = fc_els_rtv_rx,
                   1204:        .detect         = fc_els_rtv_detect,
                   1205: };
                   1206: 
                   1207: /******************************************************************************
                   1208:  *
                   1209:  * ECHO
                   1210:  *
                   1211:  ******************************************************************************
                   1212:  */
                   1213: 
                   1214: /** ECHO request data */
                   1215: struct fc_echo_request_frame {
                   1216:        /** ECHO frame header */
                   1217:        struct fc_echo_frame_header echo;
                   1218:        /** Magic marker */
                   1219:        uint32_t magic;
                   1220: } __attribute__ (( packed ));
                   1221: 
                   1222: /** ECHO magic marker */
                   1223: #define FC_ECHO_MAGIC 0x69505845
                   1224: 
                   1225: /**
                   1226:  * Transmit ECHO
                   1227:  *
                   1228:  * @v els              Fibre Channel ELS transaction
                   1229:  * @ret rc             Return status code
                   1230:  */
                   1231: static int fc_els_echo_tx ( struct fc_els *els ) {
                   1232:        struct fc_echo_request_frame echo;
                   1233: 
                   1234:        /* Construct ECHO */
                   1235:        memset ( &echo, 0, sizeof ( echo ) );
                   1236:        echo.echo.command = FC_ELS_ECHO;
                   1237:        echo.magic = htonl ( FC_ECHO_MAGIC );
                   1238: 
                   1239:        /* Transmit ECHO */
                   1240:        return fc_els_tx ( els, &echo, sizeof ( echo ) );
                   1241: }
                   1242: 
                   1243: /**
                   1244:  * Receive ECHO request
                   1245:  *
                   1246:  * @v els              Fibre Channel ELS transaction
                   1247:  * @v data             ELS frame
                   1248:  * @v len              Length of ELS frame
                   1249:  * @ret rc             Return status code
                   1250:  */
                   1251: static int fc_els_echo_rx_request ( struct fc_els *els, void *data,
                   1252:                                    size_t len ) {
                   1253:        struct {
                   1254:                struct fc_echo_frame_header echo;
                   1255:                char payload[ len - sizeof ( struct fc_echo_frame_header ) ];
                   1256:        } *echo = data;
                   1257:        int rc;
                   1258: 
                   1259:        DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
                   1260: 
                   1261:        /* Transmit response */
                   1262:        echo->echo.command = FC_ELS_LS_ACC;
                   1263:        if ( ( rc = fc_els_tx ( els, echo, sizeof ( *echo ) ) ) != 0 )
                   1264:                return rc;
                   1265: 
                   1266:        /* Nothing to do */
                   1267:        return 0;
                   1268: }
                   1269: 
                   1270: /**
                   1271:  * Receive ECHO response
                   1272:  *
                   1273:  * @v els              Fibre Channel ELS transaction
                   1274:  * @v data             ELS frame
                   1275:  * @v len              Length of ELS frame
                   1276:  * @ret rc             Return status code
                   1277:  */
                   1278: static int fc_els_echo_rx_response ( struct fc_els *els, void *data,
                   1279:                                     size_t len ) {
                   1280:        struct fc_echo_request_frame *echo = data;
                   1281: 
                   1282:        DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
                   1283: 
                   1284:        /* Check response is correct */
                   1285:        if ( ( len != sizeof ( *echo ) ) ||
                   1286:             ( echo->magic != htonl ( FC_ECHO_MAGIC ) ) ) {
                   1287:                DBGC ( els, FCELS_FMT " received bad echo response\n",
                   1288:                       FCELS_ARGS ( els ) );
                   1289:                DBGC_HDA ( els, 0, data, len );
                   1290:                return -EIO;
                   1291:        }
                   1292: 
                   1293:        return 0;
                   1294: }
                   1295: 
                   1296: /**
                   1297:  * Receive ECHO
                   1298:  *
                   1299:  * @v els              Fibre Channel ELS transaction
                   1300:  * @v data             ELS frame
                   1301:  * @v len              Length of ELS frame
                   1302:  * @ret rc             Return status code
                   1303:  */
                   1304: static int fc_els_echo_rx ( struct fc_els *els, void *data, size_t len ) {
                   1305: 
                   1306:        if ( fc_els_is_request ( els ) ) {
                   1307:                return fc_els_echo_rx_response ( els, data, len );
                   1308:        } else {
                   1309:                return fc_els_echo_rx_request ( els, data, len );
                   1310:        }
                   1311: }
                   1312: 
                   1313: /**
                   1314:  * Detect ECHO
                   1315:  *
                   1316:  * @v els              Fibre Channel ELS transaction
                   1317:  * @v data             ELS frame
                   1318:  * @v len              Length of ELS frame
                   1319:  * @ret rc             Return status code
                   1320:  */
                   1321: static int fc_els_echo_detect ( struct fc_els *els __unused, const void *data,
                   1322:                                size_t len __unused ) {
                   1323:        const struct fc_echo_frame_header *echo = data;
                   1324: 
                   1325:        /* Check for ECHO */
                   1326:        if ( echo->command != FC_ELS_ECHO )
                   1327:                return -EINVAL;
                   1328: 
                   1329:        return 0;
                   1330: }
                   1331: 
                   1332: /** ECHO ELS handler */
                   1333: struct fc_els_handler fc_els_echo_handler __fc_els_handler = {
                   1334:        .name           = "ECHO",
                   1335:        .tx             = fc_els_echo_tx,
                   1336:        .rx             = fc_els_echo_rx,
                   1337:        .detect         = fc_els_echo_detect,
                   1338: };

unix.superglobalmegacorp.com

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