Annotation of qemu/roms/ipxe/src/net/fcp.c, revision 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.