Annotation of qemu/roms/ipxe/src/net/fcp.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 <stdint.h>
                     23: #include <stdlib.h>
                     24: #include <string.h>
                     25: #include <errno.h>
                     26: #include <stdio.h>
                     27: #include <assert.h>
                     28: #include <byteswap.h>
                     29: #include <ipxe/refcnt.h>
                     30: #include <ipxe/list.h>
                     31: #include <ipxe/interface.h>
                     32: #include <ipxe/xfer.h>
                     33: #include <ipxe/iobuf.h>
                     34: #include <ipxe/open.h>
                     35: #include <ipxe/process.h>
                     36: #include <ipxe/uri.h>
                     37: #include <ipxe/acpi.h>
                     38: #include <ipxe/scsi.h>
                     39: #include <ipxe/device.h>
                     40: #include <ipxe/edd.h>
                     41: #include <ipxe/fc.h>
                     42: #include <ipxe/fcels.h>
                     43: #include <ipxe/fcp.h>
                     44: 
                     45: /** @file
                     46:  *
                     47:  * Fibre Channel Protocol
                     48:  *
                     49:  */
                     50: 
                     51: /* Disambiguate the various error causes */
                     52: #define ERANGE_READ_DATA_ORDERING \
                     53:        __einfo_error ( EINFO_ERANGE_READ_DATA_ORDERING )
                     54: #define EINFO_ERANGE_READ_DATA_ORDERING \
                     55:        __einfo_uniqify ( EINFO_ERANGE, 0x01, "Read data out of order" )
                     56: #define ERANGE_READ_DATA_OVERRUN \
                     57:        __einfo_error ( EINFO_ERANGE_READ_DATA_OVERRUN )
                     58: #define EINFO_ERANGE_READ_DATA_OVERRUN \
                     59:        __einfo_uniqify ( EINFO_ERANGE, 0x02, "Read data overrun" )
                     60: #define ERANGE_WRITE_DATA_STUCK \
                     61:        __einfo_error ( EINFO_ERANGE_WRITE_DATA_STUCK )
                     62: #define EINFO_ERANGE_WRITE_DATA_STUCK \
                     63:        __einfo_uniqify ( EINFO_ERANGE, 0x03, "Write data stuck" )
                     64: #define ERANGE_WRITE_DATA_OVERRUN \
                     65:        __einfo_error ( EINFO_ERANGE_WRITE_DATA_OVERRUN )
                     66: #define EINFO_ERANGE_WRITE_DATA_OVERRUN \
                     67:        __einfo_uniqify ( EINFO_ERANGE, 0x04, "Write data overrun" )
                     68: #define ERANGE_DATA_UNDERRUN \
                     69:        __einfo_error ( EINFO_ERANGE_DATA_UNDERRUN )
                     70: #define EINFO_ERANGE_DATA_UNDERRUN \
                     71:        __einfo_uniqify ( EINFO_ERANGE, 0x05, "Data underrun" )
                     72: 
                     73: /******************************************************************************
                     74:  *
                     75:  * PRLI
                     76:  *
                     77:  ******************************************************************************
                     78:  */
                     79: 
                     80: struct fc_els_prli_descriptor fcp_prli_descriptor __fc_els_prli_descriptor;
                     81: 
                     82: /**
                     83:  * Transmit FCP PRLI
                     84:  *
                     85:  * @v els              Fibre Channel ELS transaction
                     86:  * @ret rc             Return status code
                     87:  */
                     88: static int fcp_prli_tx ( struct fc_els *els ) {
                     89:        struct fcp_prli_service_parameters param;
                     90: 
                     91:        /* Build service parameter page */
                     92:        memset ( &param, 0, sizeof ( param ) );
                     93:        param.flags = htonl ( FCP_PRLI_NO_READ_RDY | FCP_PRLI_INITIATOR );
                     94: 
                     95:        return fc_els_prli_tx ( els, &fcp_prli_descriptor, &param );
                     96: }
                     97: 
                     98: /**
                     99:  * Receive FCP PRLI
                    100:  *
                    101:  * @v els              Fibre Channel ELS transaction
                    102:  * @v frame            ELS frame
                    103:  * @v len              Length of ELS frame
                    104:  * @ret rc             Return status code
                    105:  */
                    106: static int fcp_prli_rx ( struct fc_els *els, void *data, size_t len ) {
                    107:        return fc_els_prli_rx ( els, &fcp_prli_descriptor, data, len );
                    108: }
                    109: 
                    110: /**
                    111:  * Detect FCP PRLI
                    112:  *
                    113:  * @v els              Fibre Channel ELS transaction
                    114:  * @v data             ELS frame
                    115:  * @v len              Length of ELS frame
                    116:  * @ret rc             Return status code
                    117:  */
                    118: static int fcp_prli_detect ( struct fc_els *els, const void *data,
                    119:                             size_t len ) {
                    120:        return fc_els_prli_detect ( els, &fcp_prli_descriptor, data, len );
                    121: }
                    122: 
                    123: /** FCP PRLI ELS handler */
                    124: struct fc_els_handler fcp_prli_handler __fc_els_handler = {
                    125:        .name           = "PRLI-FCP",
                    126:        .tx             = fcp_prli_tx,
                    127:        .rx             = fcp_prli_rx,
                    128:        .detect         = fcp_prli_detect,
                    129: };
                    130: 
                    131: /** FCP PRLI descriptor */
                    132: struct fc_els_prli_descriptor fcp_prli_descriptor __fc_els_prli_descriptor = {
                    133:        .type           = FC_TYPE_FCP,
                    134:        .param_len      = sizeof ( struct fcp_prli_service_parameters ),
                    135:        .handler        = &fcp_prli_handler,
                    136: };
                    137: 
                    138: /******************************************************************************
                    139:  *
                    140:  * FCP devices and commands
                    141:  *
                    142:  ******************************************************************************
                    143:  */
                    144: 
                    145: /** An FCP device */
                    146: struct fcp_device {
                    147:        /** Reference count */
                    148:        struct refcnt refcnt;
                    149:        /** Fibre Channel upper-layer protocol */
                    150:        struct fc_ulp *ulp;
                    151:        /** SCSI command issuing interface */
                    152:        struct interface scsi;
                    153:        /** List of active commands */
                    154:        struct list_head fcpcmds;
                    155: 
                    156:        /** Fibre Channel WWN (for boot firmware table) */
                    157:        struct fc_name wwn;
                    158:        /** SCSI LUN (for boot firmware table) */
                    159:        struct scsi_lun lun;
                    160: };
                    161: 
                    162: /** An FCP command */
                    163: struct fcp_command {
                    164:        /** Reference count */
                    165:        struct refcnt refcnt;
                    166:        /** FCP SCSI device */
                    167:        struct fcp_device *fcpdev;
                    168:        /** List of active commands */
                    169:        struct list_head list;
                    170:        /** SCSI command interface */
                    171:        struct interface scsi;
                    172:        /** Fibre Channel exchange interface */
                    173:        struct interface xchg;
                    174:        /** Send process */
                    175:        struct process process;
                    176:        /** Send current IU
                    177:         *
                    178:         * @v fcpcmd    FCP command
                    179:         * @ret rc      Return status code
                    180:         */
                    181:        int ( * send ) ( struct fcp_command *fcpcmd );
                    182:        /** SCSI command */
                    183:        struct scsi_cmd command;
                    184:        /** Data offset within command */
                    185:        size_t offset;
                    186:        /** Length of data remaining to be sent within this IU */
                    187:        size_t remaining;
                    188:        /** Exchange ID */
                    189:        uint16_t xchg_id;
                    190: };
                    191: 
                    192: /**
                    193:  * Get reference to FCP device
                    194:  *
                    195:  * @v fcpdev           FCP device
                    196:  * @ret fcpdev         FCP device
                    197:  */
                    198: static inline __attribute__ (( always_inline )) struct fcp_device *
                    199: fcpdev_get ( struct fcp_device *fcpdev ) {
                    200:        ref_get ( &fcpdev->refcnt );
                    201:        return fcpdev;
                    202: }
                    203: 
                    204: /**
                    205:  * Drop reference to FCP device
                    206:  *
                    207:  * @v fcpdev           FCP device
                    208:  */
                    209: static inline __attribute__ (( always_inline )) void
                    210: fcpdev_put ( struct fcp_device *fcpdev ) {
                    211:        ref_put ( &fcpdev->refcnt );
                    212: }
                    213: 
                    214: /**
                    215:  * Get reference to FCP command
                    216:  *
                    217:  * @v fcpcmd           FCP command
                    218:  * @ret fcpcmd         FCP command
                    219:  */
                    220: static inline __attribute__ (( always_inline )) struct fcp_command *
                    221: fcpcmd_get ( struct fcp_command *fcpcmd ) {
                    222:        ref_get ( &fcpcmd->refcnt );
                    223:        return fcpcmd;
                    224: }
                    225: 
                    226: /**
                    227:  * Drop reference to FCP command
                    228:  *
                    229:  * @v fcpcmd           FCP command
                    230:  */
                    231: static inline __attribute__ (( always_inline )) void
                    232: fcpcmd_put ( struct fcp_command *fcpcmd ) {
                    233:        ref_put ( &fcpcmd->refcnt );
                    234: }
                    235: 
                    236: /**
                    237:  * Start FCP command sending
                    238:  *
                    239:  * @v fcpcmd           FCP command
                    240:  * @v send             Send method
                    241:  */
                    242: static inline __attribute__ (( always_inline )) void
                    243: fcpcmd_start_send ( struct fcp_command *fcpcmd,
                    244:                    int ( * send ) ( struct fcp_command *fcpcmd ) ) {
                    245:        fcpcmd->send = send;
                    246:        process_add ( &fcpcmd->process );
                    247: }
                    248: 
                    249: /**
                    250:  * Stop FCP command sending
                    251:  *
                    252:  * @v fcpcmd           FCP command
                    253:  */
                    254: static inline __attribute__ (( always_inline )) void
                    255: fcpcmd_stop_send ( struct fcp_command *fcpcmd ) {
                    256:        process_del ( &fcpcmd->process );
                    257: }
                    258: 
                    259: /**
                    260:  * Free FCP command
                    261:  *
                    262:  * @v refcnt           Reference count
                    263:  */
                    264: static void fcpcmd_free ( struct refcnt *refcnt ) {
                    265:        struct fcp_command *fcpcmd =
                    266:                container_of ( refcnt, struct fcp_command, refcnt );
                    267: 
                    268:        /* Remove from list of commands */
                    269:        list_del ( &fcpcmd->list );
                    270:        fcpdev_put ( fcpcmd->fcpdev );
                    271: 
                    272:        /* Free command */
                    273:        free ( fcpcmd );
                    274: }
                    275: 
                    276: /**
                    277:  * Close FCP command
                    278:  *
                    279:  * @v fcpcmd           FCP command
                    280:  * @v rc               Reason for close
                    281:  */
                    282: static void fcpcmd_close ( struct fcp_command *fcpcmd, int rc ) {
                    283:        struct fcp_device *fcpdev = fcpcmd->fcpdev;
                    284: 
                    285:        if ( rc != 0 ) {
                    286:                DBGC ( fcpdev, "FCP %p xchg %04x closed: %s\n",
                    287:                       fcpdev, fcpcmd->xchg_id, strerror ( rc ) );
                    288:        }
                    289: 
                    290:        /* Stop sending */
                    291:        fcpcmd_stop_send ( fcpcmd );
                    292: 
                    293:        /* Shut down interfaces */
                    294:        intf_shutdown ( &fcpcmd->scsi, rc );
                    295:        intf_shutdown ( &fcpcmd->xchg, rc );
                    296: }
                    297: 
                    298: /**
                    299:  * Close FCP command in error
                    300:  *
                    301:  * @v fcpcmd           FCP command
                    302:  * @v rc               Reason for close
                    303:  */
                    304: static void fcpcmd_close_err ( struct fcp_command *fcpcmd, int rc ) {
                    305:        if ( rc == 0 )
                    306:                rc = -EPIPE;
                    307:        fcpcmd_close ( fcpcmd, rc );
                    308: }
                    309: 
                    310: /**
                    311:  * Send FCP command IU
                    312:  *
                    313:  * @v fcpcmd           FCP command
                    314:  * @ret rc             Return status code
                    315:  */
                    316: static int fcpcmd_send_cmnd ( struct fcp_command *fcpcmd ) {
                    317:        struct fcp_device *fcpdev = fcpcmd->fcpdev;
                    318:        struct scsi_cmd *command = &fcpcmd->command;
                    319:        struct io_buffer *iobuf;
                    320:        struct fcp_cmnd *cmnd;
                    321:        struct xfer_metadata meta;
                    322:        int rc;
                    323: 
                    324:        /* Sanity check */
                    325:        if ( command->data_in_len && command->data_out_len ) {
                    326:                DBGC ( fcpdev, "FCP %p xchg %04x cannot handle bidirectional "
                    327:                       "command\n", fcpdev, fcpcmd->xchg_id );
                    328:                return -ENOTSUP;
                    329:        }
                    330: 
                    331:        /* Allocate I/O buffer */
                    332:        iobuf = xfer_alloc_iob ( &fcpcmd->xchg, sizeof ( *cmnd ) );
                    333:        if ( ! iobuf ) {
                    334:                DBGC ( fcpdev, "FCP %p xchg %04x cannot allocate command IU\n",
                    335:                       fcpdev, fcpcmd->xchg_id );
                    336:                return -ENOMEM;
                    337:        }
                    338: 
                    339:        /* Construct command IU frame */
                    340:        cmnd = iob_put ( iobuf, sizeof ( *cmnd ) );
                    341:        memset ( cmnd, 0, sizeof ( *cmnd ) );
                    342:        memcpy ( &cmnd->lun, &command->lun, sizeof ( cmnd->lun ) );
                    343:        assert ( ! ( command->data_in_len && command->data_out_len ) );
                    344:        if ( command->data_in_len )
                    345:                cmnd->dirn |= FCP_CMND_RDDATA;
                    346:        if ( command->data_out_len )
                    347:                cmnd->dirn |= FCP_CMND_WRDATA;
                    348:        memcpy ( &cmnd->cdb, &fcpcmd->command.cdb, sizeof ( cmnd->cdb ) );
                    349:        cmnd->len = htonl ( command->data_in_len + command->data_out_len );
                    350:        memset ( &meta, 0, sizeof ( meta ) );
                    351:        meta.flags = ( XFER_FL_CMD_STAT | XFER_FL_OVER );
                    352:        DBGC2 ( fcpdev, "FCP %p xchg %04x CMND " SCSI_CDB_FORMAT " %04x\n",
                    353:                fcpdev, fcpcmd->xchg_id, SCSI_CDB_DATA ( cmnd->cdb ),
                    354:                ntohl ( cmnd->len ) );
                    355: 
                    356:        /* No further data to send within this IU */
                    357:        fcpcmd_stop_send ( fcpcmd );
                    358: 
                    359:        /* Send command IU frame */
                    360:        if ( ( rc = xfer_deliver ( &fcpcmd->xchg, iob_disown ( iobuf ),
                    361:                                   &meta ) ) != 0 ) {
                    362:                DBGC ( fcpdev, "FCP %p xchg %04x cannot deliver command IU: "
                    363:                       "%s\n", fcpdev, fcpcmd->xchg_id, strerror ( rc ) );
                    364:                return rc;
                    365:        }
                    366: 
                    367:        return 0;
                    368: }
                    369: 
                    370: /**
                    371:  * Handle FCP read data IU
                    372:  *
                    373:  * @v fcpcmd           FCP command
                    374:  * @v iobuf            I/O buffer
                    375:  * @v meta             Data transfer metadata
                    376:  * @ret rc             Return status code
                    377:  */
                    378: static int fcpcmd_recv_rddata ( struct fcp_command *fcpcmd,
                    379:                                struct io_buffer *iobuf,
                    380:                                struct xfer_metadata *meta ) {
                    381:        struct fcp_device *fcpdev = fcpcmd->fcpdev;
                    382:        struct scsi_cmd *command = &fcpcmd->command;
                    383:        size_t offset = meta->offset;
                    384:        size_t len = iob_len ( iobuf );
                    385:        int rc;
                    386: 
                    387:        /* Sanity checks */
                    388:        if ( ! ( meta->flags & XFER_FL_ABS_OFFSET ) ) {
                    389:                DBGC ( fcpdev, "FCP %p xchg %04x read data missing offset\n",
                    390:                       fcpdev, fcpcmd->xchg_id );
                    391:                rc = -ERANGE_READ_DATA_ORDERING;
                    392:                goto done;
                    393:        }
                    394:        if ( offset != fcpcmd->offset ) {
                    395:                DBGC ( fcpdev, "FCP %p xchg %04x read data out of order "
                    396:                       "(expected %zd, received %zd)\n",
                    397:                       fcpdev, fcpcmd->xchg_id, fcpcmd->offset, offset );
                    398:                rc = -ERANGE_READ_DATA_ORDERING;
                    399:                goto done;
                    400:        }
                    401:        if ( ( offset + len ) > command->data_in_len ) {
                    402:                DBGC ( fcpdev, "FCP %p xchg %04x read data overrun (max %zd, "
                    403:                       "received %zd)\n", fcpdev, fcpcmd->xchg_id,
                    404:                       command->data_in_len, ( offset + len ) );
                    405:                rc = -ERANGE_READ_DATA_OVERRUN;
                    406:                goto done;
                    407:        }
                    408:        DBGC2 ( fcpdev, "FCP %p xchg %04x RDDATA [%08zx,%08zx)\n",
                    409:                fcpdev, fcpcmd->xchg_id, offset, ( offset + len ) );
                    410: 
                    411:        /* Copy to user buffer */
                    412:        copy_to_user ( command->data_in, offset, iobuf->data, len );
                    413:        fcpcmd->offset += len;
                    414:        assert ( fcpcmd->offset <= command->data_in_len );
                    415: 
                    416:        rc = 0;
                    417:  done:
                    418:        free_iob ( iobuf );
                    419:        return rc;
                    420: }
                    421: 
                    422: /**
                    423:  * Send FCP write data IU
                    424:  *
                    425:  * @v fcpcmd           FCP command
                    426:  * @ret rc             Return status code
                    427:  */
                    428: static int fcpcmd_send_wrdata ( struct fcp_command *fcpcmd ) {
                    429:        struct fcp_device *fcpdev = fcpcmd->fcpdev;
                    430:        struct scsi_cmd *command = &fcpcmd->command;
                    431:        struct io_buffer *iobuf;
                    432:        struct xfer_metadata meta;
                    433:        size_t len;
                    434:        int rc;
                    435: 
                    436:        /* Calculate length to be sent */
                    437:        len = xfer_window ( &fcpcmd->xchg );
                    438:        if ( len > fcpcmd->remaining )
                    439:                len = fcpcmd->remaining;
                    440: 
                    441:        /* Sanity checks */
                    442:        if ( len == 0 ) {
                    443:                DBGC ( fcpdev, "FCP %p xchg %04x write data stuck\n",
                    444:                       fcpdev, fcpcmd->xchg_id );
                    445:                return -ERANGE_WRITE_DATA_STUCK;
                    446:        }
                    447:        if ( ( fcpcmd->offset + len ) > command->data_out_len ) {
                    448:                DBGC ( fcpdev, "FCP %p xchg %04x write data overrun (max %zd, "
                    449:                       "requested %zd)\n", fcpdev, fcpcmd->xchg_id,
                    450:                       command->data_out_len, ( fcpcmd->offset + len ) );
                    451:                return -ERANGE_WRITE_DATA_OVERRUN;
                    452:        }
                    453: 
                    454:        /* Allocate I/O buffer */
                    455:        iobuf = xfer_alloc_iob ( &fcpcmd->xchg, len );
                    456:        if ( ! iobuf ) {
                    457:                DBGC ( fcpdev, "FCP %p xchg %04x cannot allocate write data "
                    458:                       "IU for %zd bytes\n", fcpdev, fcpcmd->xchg_id, len );
                    459:                return -ENOMEM;
                    460:        }
                    461: 
                    462:        /* Construct data IU frame */
                    463:        copy_from_user ( iob_put ( iobuf, len ), command->data_out,
                    464:                         fcpcmd->offset, len );
                    465:        memset ( &meta, 0, sizeof ( meta ) );
                    466:        meta.flags = ( XFER_FL_RESPONSE | XFER_FL_ABS_OFFSET );
                    467:        meta.offset = fcpcmd->offset;
                    468:        DBGC2 ( fcpdev, "FCP %p xchg %04x WRDATA [%08zx,%04zx)\n",
                    469:                fcpdev, fcpcmd->xchg_id, fcpcmd->offset,
                    470:                ( fcpcmd->offset + iob_len ( iobuf ) ) );
                    471: 
                    472:        /* Calculate amount of data remaining to be sent within this IU */
                    473:        assert ( len <= fcpcmd->remaining );
                    474:        fcpcmd->offset += len;
                    475:        fcpcmd->remaining -= len;
                    476:        assert ( fcpcmd->offset <= command->data_out_len );
                    477:        if ( fcpcmd->remaining == 0 ) {
                    478:                fcpcmd_stop_send ( fcpcmd );
                    479:                meta.flags |= XFER_FL_OVER;
                    480:        }
                    481: 
                    482:        /* Send data IU frame */
                    483:        if ( ( rc = xfer_deliver ( &fcpcmd->xchg, iob_disown ( iobuf ),
                    484:                                   &meta ) ) != 0 ) {
                    485:                DBGC ( fcpdev, "FCP %p xchg %04x cannot deliver write data "
                    486:                       "IU: %s\n", fcpdev, fcpcmd->xchg_id, strerror ( rc ) );
                    487:                return rc;
                    488:        }
                    489: 
                    490:        return 0;
                    491: }
                    492: 
                    493: /**
                    494:  * Handle FCP transfer ready IU
                    495:  *
                    496:  * @v fcpcmd           FCP command
                    497:  * @v iobuf            I/O buffer
                    498:  * @v meta             Data transfer metadata
                    499:  * @ret rc             Return status code
                    500:  */
                    501: static int fcpcmd_recv_xfer_rdy ( struct fcp_command *fcpcmd,
                    502:                                  struct io_buffer *iobuf,
                    503:                                  struct xfer_metadata *meta __unused ) {
                    504:        struct fcp_device *fcpdev = fcpcmd->fcpdev;
                    505:        struct fcp_xfer_rdy *xfer_rdy = iobuf->data;
                    506:        int rc;
                    507: 
                    508:        /* Sanity checks */
                    509:        if ( iob_len ( iobuf ) != sizeof ( *xfer_rdy ) ) {
                    510:                DBGC ( fcpdev, "FCP %p xchg %04x received invalid transfer "
                    511:                       "ready IU:\n", fcpdev, fcpcmd->xchg_id );
                    512:                DBGC_HDA ( fcpdev, 0, iobuf->data, iob_len ( iobuf ) );
                    513:                rc = -EPROTO;
                    514:                goto done;
                    515:        }
                    516:        if ( ntohl ( xfer_rdy->offset ) != fcpcmd->offset ) {
                    517:                /* We do not advertise out-of-order delivery */
                    518:                DBGC ( fcpdev, "FCP %p xchg %04x cannot support out-of-order "
                    519:                       "delivery (expected %zd, requested %d)\n",
                    520:                       fcpdev, fcpcmd->xchg_id, fcpcmd->offset,
                    521:                       ntohl ( xfer_rdy->offset ) );
                    522:                rc = -EPROTO;
                    523:                goto done;
                    524:        }
                    525:        DBGC2 ( fcpdev, "FCP %p xchg %04x XFER_RDY [%08x,%08x)\n",
                    526:                fcpdev, fcpcmd->xchg_id, ntohl ( xfer_rdy->offset ),
                    527:                ( ntohl ( xfer_rdy->offset ) + ntohl ( xfer_rdy->len ) ) );
                    528: 
                    529:        /* Start sending requested data */
                    530:        fcpcmd->remaining = ntohl ( xfer_rdy->len );
                    531:        fcpcmd_start_send ( fcpcmd, fcpcmd_send_wrdata );
                    532: 
                    533:        rc = 0;
                    534:  done:
                    535:        free_iob ( iobuf );
                    536:        return rc;
                    537: }
                    538: 
                    539: /**
                    540:  * Handle FCP response IU
                    541:  *
                    542:  * @v fcpcmd           FCP command
                    543:  * @v iobuf            I/O buffer
                    544:  * @v meta             Data transfer metadata
                    545:  * @ret rc             Return status code
                    546:  */
                    547: static int fcpcmd_recv_rsp ( struct fcp_command *fcpcmd,
                    548:                             struct io_buffer *iobuf,
                    549:                             struct xfer_metadata *meta __unused ) {
                    550:        struct fcp_device *fcpdev = fcpcmd->fcpdev;
                    551:        struct scsi_cmd *command = &fcpcmd->command;
                    552:        struct fcp_rsp *rsp = iobuf->data;
                    553:        struct scsi_sense *sense;
                    554:        struct scsi_rsp response;
                    555:        int rc;
                    556: 
                    557:        /* Sanity check */
                    558:        if ( ( iob_len ( iobuf ) < sizeof ( *rsp ) ) ||
                    559:             ( iob_len ( iobuf ) < ( sizeof ( *rsp ) +
                    560:                                     fcp_rsp_response_data_len ( rsp ) +
                    561:                                     fcp_rsp_sense_data_len ( rsp ) ) ) ) {
                    562:                DBGC ( fcpdev, "FCP %p xchg %04x received invalid response "
                    563:                       "IU:\n", fcpdev, fcpcmd->xchg_id );
                    564:                DBGC_HDA ( fcpdev, 0, iobuf->data, iob_len ( iobuf ) );
                    565:                rc = -EPROTO;
                    566:                goto done;
                    567:        }
                    568:        DBGC2 ( fcpdev, "FCP %p xchg %04x RSP stat %02x resid %08x flags %02x"
                    569:                "%s%s%s%s\n", fcpdev, fcpcmd->xchg_id, rsp->status,
                    570:                ntohl ( rsp->residual ), rsp->flags,
                    571:                ( ( rsp->flags & FCP_RSP_RESPONSE_LEN_VALID ) ? " resp" : "" ),
                    572:                ( ( rsp->flags & FCP_RSP_SENSE_LEN_VALID ) ? " sense" : "" ),
                    573:                ( ( rsp->flags & FCP_RSP_RESIDUAL_OVERRUN ) ? " over" : "" ),
                    574:                ( ( rsp->flags & FCP_RSP_RESIDUAL_UNDERRUN ) ? " under" : "" ));
                    575:        if ( fcp_rsp_response_data ( rsp ) ) {
                    576:                DBGC2 ( fcpdev, "FCP %p xchg %04x response data:\n",
                    577:                        fcpdev, fcpcmd->xchg_id );
                    578:                DBGC2_HDA ( fcpdev, 0, fcp_rsp_response_data ( rsp ),
                    579:                            fcp_rsp_response_data_len ( rsp ) );
                    580:        }
                    581:        if ( fcp_rsp_sense_data ( rsp ) ) {
                    582:                DBGC2 ( fcpdev, "FCP %p xchg %04x sense data:\n",
                    583:                        fcpdev, fcpcmd->xchg_id );
                    584:                DBGC2_HDA ( fcpdev, 0, fcp_rsp_sense_data ( rsp ),
                    585:                            fcp_rsp_sense_data_len ( rsp ) );
                    586:        }
                    587: 
                    588:        /* Check for locally-detected command underrun */
                    589:        if ( ( rsp->status == 0 ) &&
                    590:             ( fcpcmd->offset != ( command->data_in_len +
                    591:                                   command->data_out_len ) ) ) {
                    592:                DBGC ( fcpdev, "FCP %p xchg %04x data underrun (expected %zd, "
                    593:                       "got %zd)\n", fcpdev, fcpcmd->xchg_id,
                    594:                       ( command->data_in_len + command->data_out_len ),
                    595:                       fcpcmd->offset );
                    596:                rc = -ERANGE_DATA_UNDERRUN;
                    597:                goto done;
                    598:        }
                    599: 
                    600:        /* Build SCSI response */
                    601:        memset ( &response, 0, sizeof ( response ) );
                    602:        response.status = rsp->status;
                    603:        if ( rsp->flags & ( FCP_RSP_RESIDUAL_OVERRUN |
                    604:                            FCP_RSP_RESIDUAL_UNDERRUN ) ) {
                    605:                response.overrun = ntohl ( rsp->residual );
                    606:                if ( rsp->flags & FCP_RSP_RESIDUAL_UNDERRUN )
                    607:                        response.overrun = -response.overrun;
                    608:        }
                    609:        if ( ( sense = fcp_rsp_sense_data ( rsp ) ) != NULL )
                    610:                memcpy ( &response.sense, sense, sizeof ( response.sense ) );
                    611: 
                    612:        /* Free buffer before sending response, to minimise
                    613:         * out-of-memory errors.
                    614:         */
                    615:        free_iob ( iob_disown ( iobuf ) );
                    616: 
                    617:        /* Send SCSI response */
                    618:        scsi_response ( &fcpcmd->scsi, &response );
                    619: 
                    620:        /* Terminate command */
                    621:        fcpcmd_close ( fcpcmd, 0 );
                    622: 
                    623:        rc = 0;
                    624:  done:
                    625:        free_iob ( iobuf );
                    626:        return rc;
                    627: }
                    628: 
                    629: /**
                    630:  * Handle unknown FCP IU
                    631:  *
                    632:  * @v fcpcmd           FCP command
                    633:  * @v iobuf            I/O buffer
                    634:  * @v meta             Data transfer metadata
                    635:  * @ret rc             Return status code
                    636:  */
                    637: static int fcpcmd_recv_unknown ( struct fcp_command *fcpcmd,
                    638:                                 struct io_buffer *iobuf,
                    639:                                 struct xfer_metadata *meta __unused ) {
                    640:        struct fcp_device *fcpdev = fcpcmd->fcpdev;
                    641: 
                    642:        DBGC ( fcpdev, "FCP %p xchg %04x received unknown IU:\n",
                    643:               fcpdev, fcpcmd->xchg_id );
                    644:        DBGC_HDA ( fcpdev, 0, iobuf->data, iob_len ( iobuf ) );
                    645:        free_iob ( iobuf );
                    646:        return -EPROTO;
                    647: }
                    648: 
                    649: /**
                    650:  * Transmit FCP frame
                    651:  *
                    652:  * @v process          FCP command process
                    653:  */
                    654: static void fcpcmd_step ( struct process *process ) {
                    655:        struct fcp_command *fcpcmd =
                    656:                container_of ( process, struct fcp_command, process );
                    657:        int rc;
                    658: 
                    659:        /* Send the current IU */
                    660:        if ( ( rc = fcpcmd->send ( fcpcmd ) ) != 0 ) {
                    661:                /* Treat failure as a fatal error */
                    662:                fcpcmd_close ( fcpcmd, rc );
                    663:        }
                    664: }
                    665: 
                    666: /**
                    667:  * Receive FCP frame
                    668:  *
                    669:  * @v fcpcmd           FCP command
                    670:  * @v iobuf            I/O buffer
                    671:  * @v meta             Data transfer metadata
                    672:  * @ret rc             Return status code
                    673:  */
                    674: static int fcpcmd_deliver ( struct fcp_command *fcpcmd,
                    675:                            struct io_buffer *iobuf,
                    676:                            struct xfer_metadata *meta ) {
                    677:        int ( * fcpcmd_recv ) ( struct fcp_command *fcpcmd,
                    678:                                struct io_buffer *iobuf,
                    679:                                struct xfer_metadata *meta );
                    680:        int rc;
                    681: 
                    682:        /* Determine handler */
                    683:        switch ( meta->flags & ( XFER_FL_CMD_STAT | XFER_FL_RESPONSE ) ) {
                    684:        case ( XFER_FL_RESPONSE ) :
                    685:                fcpcmd_recv = fcpcmd_recv_rddata;
                    686:                break;
                    687:        case ( XFER_FL_CMD_STAT ) :
                    688:                fcpcmd_recv = fcpcmd_recv_xfer_rdy;
                    689:                break;
                    690:        case ( XFER_FL_CMD_STAT | XFER_FL_RESPONSE ) :
                    691:                fcpcmd_recv = fcpcmd_recv_rsp;
                    692:                break;
                    693:        default:
                    694:                fcpcmd_recv = fcpcmd_recv_unknown;
                    695:                break;
                    696:        }
                    697: 
                    698:        /* Handle IU */
                    699:        if ( ( rc = fcpcmd_recv ( fcpcmd, iob_disown ( iobuf ), meta ) ) != 0 ){
                    700:                /* Treat any error as fatal to the command */
                    701:                fcpcmd_close ( fcpcmd, rc );
                    702:        }
                    703: 
                    704:        return rc;
                    705: }
                    706: 
                    707: /** FCP command SCSI interface operations */
                    708: static struct interface_operation fcpcmd_scsi_op[] = {
                    709:        INTF_OP ( intf_close, struct fcp_command *, fcpcmd_close ),
                    710: };
                    711: 
                    712: /** FCP command SCSI interface descriptor */
                    713: static struct interface_descriptor fcpcmd_scsi_desc =
                    714:        INTF_DESC_PASSTHRU ( struct fcp_command, scsi, fcpcmd_scsi_op, xchg );
                    715: 
                    716: /** FCP command Fibre Channel exchange interface operations */
                    717: static struct interface_operation fcpcmd_xchg_op[] = {
                    718:        INTF_OP ( xfer_deliver, struct fcp_command *, fcpcmd_deliver ),
                    719:        INTF_OP ( intf_close, struct fcp_command *, fcpcmd_close_err ),
                    720: };
                    721: 
                    722: /** FCP command Fibre Channel exchange interface descriptor */
                    723: static struct interface_descriptor fcpcmd_xchg_desc =
                    724:        INTF_DESC_PASSTHRU ( struct fcp_command, xchg, fcpcmd_xchg_op, scsi );
                    725: 
                    726: /**
                    727:  * Issue FCP SCSI command
                    728:  *
                    729:  * @v fcpdev           FCP device
                    730:  * @v parent           Parent interface
                    731:  * @v command          SCSI command
                    732:  * @ret tag            Command tag, or negative error
                    733:  */
                    734: static int fcpdev_scsi_command ( struct fcp_device *fcpdev,
                    735:                                 struct interface *parent,
                    736:                                 struct scsi_cmd *command ) {
                    737:        struct fcp_prli_service_parameters *param = fcpdev->ulp->param;
                    738:        struct fcp_command *fcpcmd;
                    739:        int xchg_id;
                    740:        int rc;
                    741: 
                    742:        /* Check link */
                    743:        if ( ( rc = fcpdev->ulp->link.rc ) != 0 ) {
                    744:                DBGC ( fcpdev, "FCP %p could not issue command while link is "
                    745:                       "down: %s\n", fcpdev, strerror ( rc ) );
                    746:                goto err_link;
                    747:        }
                    748: 
                    749:        /* Check target capability */
                    750:        assert ( param != NULL );
                    751:        assert ( fcpdev->ulp->param_len >= sizeof ( *param ) );
                    752:        if ( ! ( param->flags & htonl ( FCP_PRLI_TARGET ) ) ) {
                    753:                DBGC ( fcpdev, "FCP %p could not issue command: not a target\n",
                    754:                       fcpdev );
                    755:                rc = -ENOTTY;
                    756:                goto err_target;
                    757:        }
                    758: 
                    759:        /* Allocate and initialise structure */
                    760:        fcpcmd = zalloc ( sizeof ( *fcpcmd ) );
                    761:        if ( ! fcpcmd ) {
                    762:                rc = -ENOMEM;
                    763:                goto err_zalloc;
                    764:        }
                    765:        ref_init ( &fcpcmd->refcnt, fcpcmd_free );
                    766:        intf_init ( &fcpcmd->scsi, &fcpcmd_scsi_desc, &fcpcmd->refcnt );
                    767:        intf_init ( &fcpcmd->xchg, &fcpcmd_xchg_desc, &fcpcmd->refcnt );
                    768:        process_init_stopped ( &fcpcmd->process, fcpcmd_step, &fcpcmd->refcnt );
                    769:        fcpcmd->fcpdev = fcpdev_get ( fcpdev );
                    770:        list_add ( &fcpcmd->list, &fcpdev->fcpcmds );
                    771:        memcpy ( &fcpcmd->command, command, sizeof ( fcpcmd->command ) );
                    772: 
                    773:        /* Create new exchange */
                    774:        if ( ( xchg_id = fc_xchg_originate ( &fcpcmd->xchg,
                    775:                                             fcpdev->ulp->peer->port,
                    776:                                             &fcpdev->ulp->peer->port_id,
                    777:                                             FC_TYPE_FCP ) ) < 0 ) {
                    778:                rc = xchg_id;
                    779:                DBGC ( fcpdev, "FCP %p could not create exchange: %s\n",
                    780:                       fcpdev, strerror ( rc ) );
                    781:                goto err_xchg_originate;
                    782:        }
                    783:        fcpcmd->xchg_id = xchg_id;
                    784: 
                    785:        /* Start sending command IU */
                    786:        fcpcmd_start_send ( fcpcmd, fcpcmd_send_cmnd );
                    787: 
                    788:        /* Attach to parent interface, mortalise self, and return */
                    789:        intf_plug_plug ( &fcpcmd->scsi, parent );
                    790:        ref_put ( &fcpcmd->refcnt );
                    791:        return ( FCP_TAG_MAGIC | fcpcmd->xchg_id );
                    792: 
                    793:  err_xchg_originate:
                    794:        fcpcmd_close ( fcpcmd, rc );
                    795:        ref_put ( &fcpcmd->refcnt );
                    796:  err_zalloc:
                    797:  err_target:
                    798:  err_link:
                    799:        return rc;
                    800: }
                    801: 
                    802: /**
                    803:  * Close FCP device
                    804:  *
                    805:  * @v fcpdev           FCP device
                    806:  * @v rc               Reason for close
                    807:  */
                    808: static void fcpdev_close ( struct fcp_device *fcpdev, int rc ) {
                    809:        struct fcp_command *fcpcmd;
                    810:        struct fcp_command *tmp;
                    811: 
                    812:        DBGC ( fcpdev, "FCP %p closed: %s\n", fcpdev, strerror ( rc ) );
                    813: 
                    814:        /* Shut down interfaces */
                    815:        intf_shutdown ( &fcpdev->scsi, rc );
                    816: 
                    817:        /* Shut down any active commands */
                    818:        list_for_each_entry_safe ( fcpcmd, tmp, &fcpdev->fcpcmds, list ) {
                    819:                fcpcmd_get ( fcpcmd );
                    820:                fcpcmd_close ( fcpcmd, rc );
                    821:                fcpcmd_put ( fcpcmd );
                    822:        }
                    823: 
                    824:        /* Drop reference to ULP */
                    825:        if ( fcpdev->ulp ) {
                    826:                fc_ulp_decrement ( fcpdev->ulp );
                    827:                fc_ulp_put ( fcpdev->ulp );
                    828:                fcpdev->ulp = NULL;
                    829:        }
                    830: }
                    831: 
                    832: /**
                    833:  * Check FCP device flow-control window
                    834:  *
                    835:  * @v fcpdev           FCP device
                    836:  * @ret len            Length of window
                    837:  */
                    838: static size_t fcpdev_window ( struct fcp_device *fcpdev ) {
                    839:        return ( fc_link_ok ( &fcpdev->ulp->link ) ? ~( ( size_t ) 0 ) : 0 );
                    840: }
                    841: 
                    842: /**
                    843:  * Describe FCP device in an ACPI table
                    844:  *
                    845:  * @v fcpdev           FCP device
                    846:  * @v acpi             ACPI table
                    847:  * @v len              Length of ACPI table
                    848:  * @ret rc             Return status code
                    849:  */
                    850: static int fcpdev_acpi_describe ( struct fcp_device *fcpdev,
                    851:                                  struct acpi_description_header *acpi,
                    852:                                  size_t len ) {
                    853: 
                    854:        DBGC ( fcpdev, "FCP %p cannot yet describe device in an ACPI table\n",
                    855:               fcpdev );
                    856:        ( void ) acpi;
                    857:        ( void ) len;
                    858:        return 0;
                    859: }
                    860: 
                    861: /**
                    862:  * Describe FCP device using EDD
                    863:  *
                    864:  * @v fcpdev           FCP device
                    865:  * @v type             EDD interface type
                    866:  * @v path             EDD device path
                    867:  * @ret rc             Return status code
                    868:  */
                    869: static int fcpdev_edd_describe ( struct fcp_device *fcpdev,
                    870:                                 struct edd_interface_type *type,
                    871:                                 union edd_device_path *path ) {
                    872:        union {
                    873:                struct fc_name fc;
                    874:                uint64_t u64;
                    875:        } wwn;
                    876:        union {
                    877:                struct scsi_lun scsi;
                    878:                uint64_t u64;
                    879:        } lun;
                    880: 
                    881:        type->type = cpu_to_le64 ( EDD_INTF_TYPE_FIBRE );
                    882:        memcpy ( &wwn.fc, &fcpdev->wwn, sizeof ( wwn.fc ) );
                    883:        path->fibre.wwn = be64_to_cpu ( wwn.u64 );
                    884:        memcpy ( &lun.scsi, &fcpdev->lun, sizeof ( lun.scsi ) );
                    885:        path->fibre.lun = be64_to_cpu ( lun.u64 );
                    886:        return 0;
                    887: }
                    888: 
                    889: /**
                    890:  * Identify device underlying FCP device
                    891:  *
                    892:  * @v fcpdev           FCP device
                    893:  * @ret device         Underlying device
                    894:  */
                    895: static struct device * fcpdev_identify_device ( struct fcp_device *fcpdev ) {
                    896: 
                    897:        /* We know the underlying device only if the link is up;
                    898:         * otherwise we don't have a port to examine.
                    899:         */
                    900:        if ( ! fc_link_ok ( &fcpdev->ulp->link ) ) {
                    901:                DBGC ( fcpdev, "FCP %p doesn't know underlying device "
                    902:                       "until link is up\n", fcpdev );
                    903:                return NULL;
                    904:        }
                    905: 
                    906:        /* Hand off to port's transport interface */
                    907:        assert ( fcpdev->ulp->peer->port != NULL );
                    908:        return identify_device ( &fcpdev->ulp->peer->port->transport );
                    909: }
                    910: 
                    911: /** FCP device SCSI interface operations */
                    912: static struct interface_operation fcpdev_scsi_op[] = {
                    913:        INTF_OP ( scsi_command, struct fcp_device *, fcpdev_scsi_command ),
                    914:        INTF_OP ( xfer_window, struct fcp_device *, fcpdev_window ),
                    915:        INTF_OP ( intf_close, struct fcp_device *, fcpdev_close ),
                    916:        INTF_OP ( acpi_describe, struct fcp_device *, fcpdev_acpi_describe ),
                    917:        INTF_OP ( edd_describe, struct fcp_device *, fcpdev_edd_describe ),
                    918:        INTF_OP ( identify_device, struct fcp_device *,
                    919:                  fcpdev_identify_device ),
                    920: };
                    921: 
                    922: /** FCP device SCSI interface descriptor */
                    923: static struct interface_descriptor fcpdev_scsi_desc =
                    924:        INTF_DESC ( struct fcp_device, scsi, fcpdev_scsi_op );
                    925: 
                    926: /**
                    927:  * Open FCP device
                    928:  *
                    929:  * @v parent           Parent interface
                    930:  * @v wwn              Fibre Channel WWN
                    931:  * @v lun              SCSI LUN
                    932:  * @ret rc             Return status code
                    933:  */
                    934: static int fcpdev_open ( struct interface *parent, struct fc_name *wwn,
                    935:                         struct scsi_lun *lun ) {
                    936:        struct fc_ulp *ulp;
                    937:        struct fcp_device *fcpdev;
                    938:        int rc;
                    939: 
                    940:        /* Get Fibre Channel ULP interface */
                    941:        ulp = fc_ulp_get_wwn_type ( wwn, FC_TYPE_FCP );
                    942:        if ( ! ulp ) {
                    943:                rc = -ENOMEM;
                    944:                goto err_ulp_get;
                    945:        }
                    946: 
                    947:        /* Allocate and initialise structure */
                    948:        fcpdev = zalloc ( sizeof ( *fcpdev ) );
                    949:        if ( ! fcpdev ) {
                    950:                rc = -ENOMEM;
                    951:                goto err_zalloc;
                    952:        }
                    953:        ref_init ( &fcpdev->refcnt, NULL );
                    954:        intf_init ( &fcpdev->scsi, &fcpdev_scsi_desc, &fcpdev->refcnt );
                    955:        INIT_LIST_HEAD ( &fcpdev->fcpcmds );
                    956:        fcpdev->ulp = fc_ulp_get ( ulp );
                    957:        fc_ulp_increment ( fcpdev->ulp );
                    958: 
                    959:        DBGC ( fcpdev, "FCP %p opened for %s\n", fcpdev, fc_ntoa ( wwn ) );
                    960: 
                    961:        /* Preserve parameters required for boot firmware table */
                    962:        memcpy ( &fcpdev->wwn, wwn, sizeof ( fcpdev->wwn ) );
                    963:        memcpy ( &fcpdev->lun, lun, sizeof ( fcpdev->lun ) );
                    964: 
                    965:        /* Attach SCSI device to parent interface */
                    966:        if ( ( rc = scsi_open ( parent, &fcpdev->scsi, lun ) ) != 0 ) {
                    967:                DBGC ( fcpdev, "FCP %p could not create SCSI device: %s\n",
                    968:                       fcpdev, strerror ( rc ) );
                    969:                goto err_scsi_open;
                    970:        }
                    971: 
                    972:        /* Drop temporary reference to ULP */
                    973:        fc_ulp_put ( ulp );
                    974: 
                    975:        /* Mortalise self and return */
                    976:        ref_put ( &fcpdev->refcnt );
                    977:        return 0;
                    978: 
                    979:  err_scsi_open:
                    980:        fcpdev_close ( fcpdev, rc );
                    981:        ref_put ( &fcpdev->refcnt );
                    982:  err_zalloc:
                    983:        fc_ulp_put ( ulp );
                    984:  err_ulp_get:
                    985:        return rc;
                    986: }
                    987: 
                    988: /******************************************************************************
                    989:  *
                    990:  * FCP URIs
                    991:  *
                    992:  ******************************************************************************
                    993:  */
                    994: 
                    995: /**
                    996:  * Parse FCP URI
                    997:  *
                    998:  * @v uri              URI
                    999:  * @ret wwn            Fibre Channel WWN
                   1000:  * @ret lun            SCSI LUN
                   1001:  * @ret rc             Return status code
                   1002:  *
                   1003:  * An FCP URI has the form "fcp:<wwn>:<lun>" or "fcp://<wwn>/<lun>"
                   1004:  */
                   1005: static int fcp_parse_uri ( struct uri *uri, struct fc_name *wwn,
                   1006:                           struct scsi_lun *lun ) {
                   1007:        char wwn_buf[ FC_NAME_STRLEN + 1 /* NUL */ ];
                   1008:        const char *wwn_text;
                   1009:        const char *lun_text;
                   1010:        int rc;
                   1011: 
                   1012:        /* Extract WWN and LUN texts from URI */
                   1013:        if ( uri->opaque ) {
                   1014:                /* "fcp:<wwn>:<lun>" */
                   1015:                if ( snprintf ( wwn_buf, sizeof ( wwn_buf ), "%s",
                   1016:                                uri->opaque ) < ( FC_NAME_STRLEN + 1 /* : */ ) )
                   1017:                        return -EINVAL;
                   1018:                if ( uri->opaque[FC_NAME_STRLEN] != ':' )
                   1019:                        return -EINVAL;
                   1020:                wwn_text = wwn_buf;
                   1021:                lun_text = &uri->opaque[FC_NAME_STRLEN + 1];
                   1022:        } else {
                   1023:                /* If host exists, path must also exist */
                   1024:                if ( ! ( uri->host && uri->path ) )
                   1025:                        return -EINVAL;
                   1026:                if ( uri->path[0] != '/' )
                   1027:                        return -EINVAL;
                   1028:                wwn_text = uri->host;
                   1029:                lun_text = ( uri->path + 1 );
                   1030:        }
                   1031: 
                   1032:        /* Parse WWN */
                   1033:        if ( ( rc = fc_aton ( wwn_text, wwn ) ) != 0 )
                   1034:                return rc;
                   1035: 
                   1036:        /* Parse LUN */
                   1037:        if ( ( rc = scsi_parse_lun ( lun_text, lun ) ) != 0 )
                   1038:                return rc;
                   1039: 
                   1040:        return 0;
                   1041: }
                   1042: 
                   1043: /**
                   1044:  * Open FCP URI
                   1045:  *
                   1046:  * @v parent           Parent interface
                   1047:  * @v uri              URI
                   1048:  * @ret rc             Return status code
                   1049:  */
                   1050: static int fcp_open ( struct interface *parent, struct uri *uri ) {
                   1051:        struct fc_name wwn;
                   1052:        struct scsi_lun lun;
                   1053:        int rc;
                   1054: 
                   1055:        /* Parse URI */
                   1056:        if ( ( rc = fcp_parse_uri ( uri, &wwn, &lun ) ) != 0 )
                   1057:                return rc;
                   1058: 
                   1059:        /* Open FCP device */
                   1060:        if ( ( rc = fcpdev_open ( parent, &wwn, &lun ) ) != 0 )
                   1061:                return rc;
                   1062: 
                   1063:        return 0;
                   1064: }
                   1065: 
                   1066: /** FCP URI opener */
                   1067: struct uri_opener fcp_uri_opener __uri_opener = {
                   1068:        .scheme = "fcp",
                   1069:        .open = fcp_open,
                   1070: };

unix.superglobalmegacorp.com

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