Annotation of qemu/roms/ipxe/src/drivers/block/srp.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (C) 2009 Fen Systems Ltd <[email protected]>.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms, with or without
        !             6:  * modification, are permitted provided that the following conditions
        !             7:  * are met:
        !             8:  *
        !             9:  *   Redistributions of source code must retain the above copyright
        !            10:  *   notice, this list of conditions and the following disclaimer.
        !            11:  *
        !            12:  *   Redistributions in binary form must reproduce the above copyright
        !            13:  *   notice, this list of conditions and the following disclaimer in
        !            14:  *   the documentation and/or other materials provided with the
        !            15:  *   distribution.
        !            16:  *
        !            17:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
        !            18:  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
        !            19:  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
        !            20:  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
        !            21:  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
        !            22:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
        !            23:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        !            24:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            25:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
        !            26:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            27:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
        !            28:  * OF THE POSSIBILITY OF SUCH DAMAGE.
        !            29:  */
        !            30: 
        !            31: FILE_LICENCE ( BSD2 );
        !            32: 
        !            33: #include <stdlib.h>
        !            34: #include <string.h>
        !            35: #include <errno.h>
        !            36: #include <ipxe/scsi.h>
        !            37: #include <ipxe/xfer.h>
        !            38: #include <ipxe/features.h>
        !            39: #include <ipxe/srp.h>
        !            40: 
        !            41: /**
        !            42:  * @file
        !            43:  *
        !            44:  * SCSI RDMA Protocol
        !            45:  *
        !            46:  */
        !            47: 
        !            48: FEATURE ( FEATURE_PROTOCOL, "SRP", DHCP_EB_FEATURE_SRP, 1 );
        !            49: 
        !            50: /** Maximum length of any initiator-to-target IU that we will send
        !            51:  *
        !            52:  * The longest IU is a SRP_CMD with no additional CDB and two direct
        !            53:  * data buffer descriptors, which comes to 80 bytes.
        !            54:  */
        !            55: #define SRP_MAX_I_T_IU_LEN 80
        !            56: 
        !            57: /* Error numbers generated by SRP login rejection */
        !            58: #define EINFO_SRP_LOGIN_REJ( reason, desc )                                  \
        !            59:        __einfo_uniqify ( EINFO_EPERM, ( (reason) & 0x0f ), desc )
        !            60: #define EPERM_UNKNOWN                                                        \
        !            61:        __einfo_error ( EINFO_EPERM_UNKNOWN )
        !            62: #define EINFO_EPERM_UNKNOWN EINFO_SRP_LOGIN_REJ (                            \
        !            63:        SRP_LOGIN_REJ_REASON_UNKNOWN,                                         \
        !            64:        "Unable to establish RDMA channel, no reason specified" )
        !            65: #define EPERM_INSUFFICIENT_RESOURCES                                         \
        !            66:        __einfo_error ( EINFO_EPERM_INSUFFICIENT_RESOURCES )
        !            67: #define EINFO_EPERM_INSUFFICIENT_RESOURCES EINFO_SRP_LOGIN_REJ (             \
        !            68:        SRP_LOGIN_REJ_REASON_INSUFFICIENT_RESOURCES,                          \
        !            69:        "Insufficient RDMA channel resources" )
        !            70: #define EPERM_BAD_MAX_I_T_IU_LEN                                             \
        !            71:        __einfo_error ( EINFO_EPERM_BAD_MAX_I_T_IU_LEN )
        !            72: #define EINFO_EPERM_BAD_MAX_I_T_IU_LEN EINFO_SRP_LOGIN_REJ (                 \
        !            73:        SRP_LOGIN_REJ_REASON_BAD_MAX_I_T_IU_LEN,                              \
        !            74:        "Requested maximum initiator to target IU length value too large" )
        !            75: #define EPERM_CANNOT_ASSOCIATE                                               \
        !            76:        __einfo_error ( EINFO_EPERM_CANNOT_ASSOCIATE )
        !            77: #define EINFO_EPERM_CANNOT_ASSOCIATE EINFO_SRP_LOGIN_REJ (                   \
        !            78:        SRP_LOGIN_REJ_REASON_CANNOT_ASSOCIATE,                                \
        !            79:        "Unable to associate RDMA channel with specified I_T nexus" )
        !            80: #define EPERM_UNSUPPORTED_BUFFER_FORMAT                                              \
        !            81:        __einfo_error ( EINFO_EPERM_UNSUPPORTED_BUFFER_FORMAT )
        !            82: #define EINFO_EPERM_UNSUPPORTED_BUFFER_FORMAT EINFO_SRP_LOGIN_REJ (          \
        !            83:        SRP_LOGIN_REJ_REASON_UNSUPPORTED_BUFFER_FORMAT,                       \
        !            84:        "One or more requested data buffer descriptor formats not supported" )
        !            85: #define EPERM_NO_MULTIPLE_CHANNELS                                           \
        !            86:        __einfo_error ( EINFO_EPERM_NO_MULTIPLE_CHANNELS )
        !            87: #define EINFO_EPERM_NO_MULTIPLE_CHANNELS EINFO_SRP_LOGIN_REJ (               \
        !            88:        SRP_LOGIN_REJ_REASON_NO_MULTIPLE_CHANNELS,                            \
        !            89:        "SRP target does not support multiple RDMA channels per I_T nexus" )
        !            90: #define EPERM_NO_MORE_CHANNELS                                               \
        !            91:        __einfo_error ( EINFO_EPERM_NO_MORE_CHANNELS )
        !            92: #define EINFO_EPERM_NO_MORE_CHANNELS EINFO_SRP_LOGIN_REJ (                   \
        !            93:        SRP_LOGIN_REJ_REASON_NO_MORE_CHANNELS,                                \
        !            94:        "RDMA channel limit reached for this initiator" )
        !            95: #define EPERM_LOGIN_REJ( reason_nibble )                                     \
        !            96:        EUNIQ ( EPERM, (reason_nibble), EPERM_UNKNOWN,                        \
        !            97:                EPERM_INSUFFICIENT_RESOURCES, EPERM_BAD_MAX_I_T_IU_LEN,       \
        !            98:                EPERM_CANNOT_ASSOCIATE, EPERM_UNSUPPORTED_BUFFER_FORMAT,      \
        !            99:                EPERM_NO_MULTIPLE_CHANNELS, EPERM_NO_MORE_CHANNELS )
        !           100: 
        !           101: /** An SRP device */
        !           102: struct srp_device {
        !           103:        /** Reference count */
        !           104:        struct refcnt refcnt;
        !           105: 
        !           106:        /** SCSI command issuing interface */
        !           107:        struct interface scsi;
        !           108:        /** Underlying data transfer interface */
        !           109:        struct interface socket;
        !           110: 
        !           111:        /** RDMA memory handle */
        !           112:        uint32_t memory_handle;
        !           113:        /** Login completed successfully */
        !           114:        int logged_in;
        !           115: 
        !           116:        /** Initiator port ID (for boot firmware table) */
        !           117:        union srp_port_id initiator;
        !           118:        /** Target port ID (for boot firmware table) */
        !           119:        union srp_port_id target;
        !           120:        /** SCSI LUN (for boot firmware table) */
        !           121:        struct scsi_lun lun;
        !           122: 
        !           123:        /** List of active commands */
        !           124:        struct list_head commands;
        !           125: };
        !           126: 
        !           127: /** An SRP command */
        !           128: struct srp_command {
        !           129:        /** Reference count */
        !           130:        struct refcnt refcnt;
        !           131:        /** SRP device */
        !           132:        struct srp_device *srpdev;
        !           133:        /** List of active commands */
        !           134:        struct list_head list;
        !           135: 
        !           136:        /** SCSI command interface */
        !           137:        struct interface scsi;
        !           138:        /** Command tag */
        !           139:        uint32_t tag;
        !           140: };
        !           141: 
        !           142: /**
        !           143:  * Get reference to SRP device
        !           144:  *
        !           145:  * @v srpdev           SRP device
        !           146:  * @ret srpdev         SRP device
        !           147:  */
        !           148: static inline __attribute__ (( always_inline )) struct srp_device *
        !           149: srpdev_get ( struct srp_device *srpdev ) {
        !           150:        ref_get ( &srpdev->refcnt );
        !           151:        return srpdev;
        !           152: }
        !           153: 
        !           154: /**
        !           155:  * Drop reference to SRP device
        !           156:  *
        !           157:  * @v srpdev           SRP device
        !           158:  */
        !           159: static inline __attribute__ (( always_inline )) void
        !           160: srpdev_put ( struct srp_device *srpdev ) {
        !           161:        ref_put ( &srpdev->refcnt );
        !           162: }
        !           163: 
        !           164: /**
        !           165:  * Get reference to SRP command
        !           166:  *
        !           167:  * @v srpcmd           SRP command
        !           168:  * @ret srpcmd         SRP command
        !           169:  */
        !           170: static inline __attribute__ (( always_inline )) struct srp_command *
        !           171: srpcmd_get ( struct srp_command *srpcmd ) {
        !           172:        ref_get ( &srpcmd->refcnt );
        !           173:        return srpcmd;
        !           174: }
        !           175: 
        !           176: /**
        !           177:  * Drop reference to SRP command
        !           178:  *
        !           179:  * @v srpcmd           SRP command
        !           180:  */
        !           181: static inline __attribute__ (( always_inline )) void
        !           182: srpcmd_put ( struct srp_command *srpcmd ) {
        !           183:        ref_put ( &srpcmd->refcnt );
        !           184: }
        !           185: 
        !           186: /**
        !           187:  * Free SRP command
        !           188:  *
        !           189:  * @v refcnt           Reference count
        !           190:  */
        !           191: static void srpcmd_free ( struct refcnt *refcnt ) {
        !           192:        struct srp_command *srpcmd =
        !           193:                container_of ( refcnt, struct srp_command, refcnt );
        !           194: 
        !           195:        assert ( list_empty ( &srpcmd->list ) );
        !           196: 
        !           197:        srpdev_put ( srpcmd->srpdev );
        !           198:        free ( srpcmd );
        !           199: }
        !           200: 
        !           201: /**
        !           202:  * Close SRP command
        !           203:  *
        !           204:  * @v srpcmd           SRP command
        !           205:  * @v rc               Reason for close
        !           206:  */
        !           207: static void srpcmd_close ( struct srp_command *srpcmd, int rc ) {
        !           208:        struct srp_device *srpdev = srpcmd->srpdev;
        !           209: 
        !           210:        if ( rc != 0 ) {
        !           211:                DBGC ( srpdev, "SRP %p tag %08x closed: %s\n",
        !           212:                       srpdev, srpcmd->tag, strerror ( rc ) );
        !           213:        }
        !           214: 
        !           215:        /* Remove from list of commands */
        !           216:        if ( ! list_empty ( &srpcmd->list ) ) {
        !           217:                list_del ( &srpcmd->list );
        !           218:                INIT_LIST_HEAD ( &srpcmd->list );
        !           219:                srpcmd_put ( srpcmd );
        !           220:        }
        !           221: 
        !           222:        /* Shut down interfaces */
        !           223:        intf_shutdown ( &srpcmd->scsi, rc );
        !           224: }
        !           225: 
        !           226: /**
        !           227:  * Close SRP device
        !           228:  *
        !           229:  * @v srpdev           SRP device
        !           230:  * @v rc               Reason for close
        !           231:  */
        !           232: static void srpdev_close ( struct srp_device *srpdev, int rc ) {
        !           233:        struct srp_command *srpcmd;
        !           234:        struct srp_command *tmp;
        !           235: 
        !           236:        if ( rc != 0 ) {
        !           237:                DBGC ( srpdev, "SRP %p closed: %s\n",
        !           238:                       srpdev, strerror ( rc ) );
        !           239:        }
        !           240: 
        !           241:        /* Shut down interfaces */
        !           242:        intf_shutdown ( &srpdev->socket, rc );
        !           243:        intf_shutdown ( &srpdev->scsi, rc );
        !           244: 
        !           245:        /* Shut down any active commands */
        !           246:        list_for_each_entry_safe ( srpcmd, tmp, &srpdev->commands, list ) {
        !           247:                srpcmd_get ( srpcmd );
        !           248:                srpcmd_close ( srpcmd, rc );
        !           249:                srpcmd_put ( srpcmd );
        !           250:        }
        !           251: }
        !           252: 
        !           253: /**
        !           254:  * Identify SRP command by tag
        !           255:  *
        !           256:  * @v srpdev           SRP device
        !           257:  * @v tag              Command tag
        !           258:  * @ret srpcmd         SRP command, or NULL
        !           259:  */
        !           260: static struct srp_command * srp_find_tag ( struct srp_device *srpdev,
        !           261:                                           uint32_t tag ) {
        !           262:        struct srp_command *srpcmd;
        !           263: 
        !           264:        list_for_each_entry ( srpcmd, &srpdev->commands, list ) {
        !           265:                if ( srpcmd->tag == tag )
        !           266:                        return srpcmd;
        !           267:        }
        !           268:        return NULL;
        !           269: }
        !           270: 
        !           271: /**
        !           272:  * Choose an SRP command tag
        !           273:  *
        !           274:  * @v srpdev           SRP device
        !           275:  * @ret tag            New tag, or negative error
        !           276:  */
        !           277: static int srp_new_tag ( struct srp_device *srpdev ) {
        !           278:        static uint16_t tag_idx;
        !           279:        unsigned int i;
        !           280: 
        !           281:        for ( i = 0 ; i < 65536 ; i++ ) {
        !           282:                tag_idx++;
        !           283:                if ( srp_find_tag ( srpdev, tag_idx ) == NULL )
        !           284:                        return tag_idx;
        !           285:        }
        !           286:        return -EADDRINUSE;
        !           287: }
        !           288: 
        !           289: /**
        !           290:  * Transmit SRP login request
        !           291:  *
        !           292:  * @v srpdev           SRP device
        !           293:  * @v initiator                Initiator port ID
        !           294:  * @v target           Target port ID
        !           295:  * @v tag              Command tag
        !           296:  * @ret rc             Return status code
        !           297:  */
        !           298: static int srp_login ( struct srp_device *srpdev, union srp_port_id *initiator,
        !           299:                       union srp_port_id *target, uint32_t tag ) {
        !           300:        struct io_buffer *iobuf;
        !           301:        struct srp_login_req *login_req;
        !           302:        int rc;
        !           303: 
        !           304:        /* Allocate I/O buffer */
        !           305:        iobuf = xfer_alloc_iob ( &srpdev->socket, sizeof ( *login_req ) );
        !           306:        if ( ! iobuf )
        !           307:                return -ENOMEM;
        !           308: 
        !           309:        /* Construct login request IU */
        !           310:        login_req = iob_put ( iobuf, sizeof ( *login_req ) );
        !           311:        memset ( login_req, 0, sizeof ( *login_req ) );
        !           312:        login_req->type = SRP_LOGIN_REQ;
        !           313:        login_req->tag.dwords[0] = htonl ( SRP_TAG_MAGIC );
        !           314:        login_req->tag.dwords[1] = htonl ( tag );
        !           315:        login_req->max_i_t_iu_len = htonl ( SRP_MAX_I_T_IU_LEN );
        !           316:        login_req->required_buffer_formats = SRP_LOGIN_REQ_FMT_DDBD;
        !           317:        memcpy ( &login_req->initiator, initiator,
        !           318:                 sizeof ( login_req->initiator ) );
        !           319:        memcpy ( &login_req->target, target, sizeof ( login_req->target ) );
        !           320: 
        !           321:        DBGC ( srpdev, "SRP %p tag %08x LOGIN_REQ:\n", srpdev, tag );
        !           322:        DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) );
        !           323: 
        !           324:        /* Send login request IU */
        !           325:        if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) {
        !           326:                DBGC ( srpdev, "SRP %p tag %08x could not send LOGIN_REQ: "
        !           327:                       "%s\n", srpdev, tag, strerror ( rc ) );
        !           328:                return rc;
        !           329:        }
        !           330: 
        !           331:        return 0;
        !           332: }
        !           333: 
        !           334: /**
        !           335:  * Receive SRP login response
        !           336:  *
        !           337:  * @v srpdev           SRP device
        !           338:  * @v data             SRP IU
        !           339:  * @v len              Length of SRP IU
        !           340:  * @ret rc             Return status code
        !           341:  */
        !           342: static int srp_login_rsp ( struct srp_device *srpdev,
        !           343:                           const void *data, size_t len ) {
        !           344:        const struct srp_login_rsp *login_rsp = data;
        !           345: 
        !           346:        /* Sanity check */
        !           347:        if ( len < sizeof ( *login_rsp ) ) {
        !           348:                DBGC ( srpdev, "SRP %p LOGIN_RSP too short (%zd bytes)\n",
        !           349:                       srpdev, len );
        !           350:                return -EINVAL;
        !           351:        }
        !           352:        DBGC ( srpdev, "SRP %p tag %08x LOGIN_RSP:\n",
        !           353:               srpdev, ntohl ( login_rsp->tag.dwords[1] ) );
        !           354:        DBGC_HDA ( srpdev, 0, data, len );
        !           355: 
        !           356:        /* Mark as logged in */
        !           357:        srpdev->logged_in = 1;
        !           358:        DBGC ( srpdev, "SRP %p logged in\n", srpdev );
        !           359: 
        !           360:        /* Notify of window change */
        !           361:        xfer_window_changed ( &srpdev->scsi );
        !           362: 
        !           363:        return 0;
        !           364: }
        !           365: 
        !           366: /**
        !           367:  * Receive SRP login rejection
        !           368:  *
        !           369:  * @v srpdev           SRP device
        !           370:  * @v data             SRP IU
        !           371:  * @v len              Length of SRP IU
        !           372:  * @ret rc             Return status code
        !           373:  */
        !           374: static int srp_login_rej ( struct srp_device *srpdev,
        !           375:                           const void *data, size_t len ) {
        !           376:        const struct srp_login_rej *login_rej = data;
        !           377:        uint32_t reason;
        !           378: 
        !           379:        /* Sanity check */
        !           380:        if ( len < sizeof ( *login_rej ) ) {
        !           381:                DBGC ( srpdev, "SRP %p LOGIN_REJ too short (%zd bytes)\n",
        !           382:                       srpdev, len );
        !           383:                return -EINVAL;
        !           384:        }
        !           385:        reason = ntohl ( login_rej->reason );
        !           386:        DBGC ( srpdev, "SRP %p tag %08x LOGIN_REJ reason %08x:\n",
        !           387:               srpdev, ntohl ( login_rej->tag.dwords[1] ), reason );
        !           388:        DBGC_HDA ( srpdev, 0, data, len );
        !           389: 
        !           390:        /* Login rejection always indicates an error */
        !           391:        return ( SRP_LOGIN_REJ_REASON_DEFINED ( reason ) ?
        !           392:                 -EPERM_LOGIN_REJ ( reason ) : -EACCES );
        !           393: }
        !           394: 
        !           395: /**
        !           396:  * Transmit SRP SCSI command
        !           397:  *
        !           398:  * @v srpdev           SRP device
        !           399:  * @v command          SCSI command
        !           400:  * @v tag              Command tag
        !           401:  * @ret rc             Return status code
        !           402:  */
        !           403: static int srp_cmd ( struct srp_device *srpdev,
        !           404:                     struct scsi_cmd *command,
        !           405:                     uint32_t tag ) {
        !           406:        struct io_buffer *iobuf;
        !           407:        struct srp_cmd *cmd;
        !           408:        struct srp_memory_descriptor *data_out;
        !           409:        struct srp_memory_descriptor *data_in;
        !           410:        int rc;
        !           411: 
        !           412:        /* Sanity check */
        !           413:        if ( ! srpdev->logged_in ) {
        !           414:                DBGC ( srpdev, "SRP %p tag %08x cannot send CMD before "
        !           415:                       "login completes\n", srpdev, tag );
        !           416:                return -EBUSY;
        !           417:        }
        !           418: 
        !           419:        /* Allocate I/O buffer */
        !           420:        iobuf = xfer_alloc_iob ( &srpdev->socket, SRP_MAX_I_T_IU_LEN );
        !           421:        if ( ! iobuf )
        !           422:                return -ENOMEM;
        !           423: 
        !           424:        /* Construct base portion */
        !           425:        cmd = iob_put ( iobuf, sizeof ( *cmd ) );
        !           426:        memset ( cmd, 0, sizeof ( *cmd ) );
        !           427:        cmd->type = SRP_CMD;
        !           428:        cmd->tag.dwords[0] = htonl ( SRP_TAG_MAGIC );
        !           429:        cmd->tag.dwords[1] = htonl ( tag );
        !           430:        memcpy ( &cmd->lun, &command->lun, sizeof ( cmd->lun ) );
        !           431:        memcpy ( &cmd->cdb, &command->cdb, sizeof ( cmd->cdb ) );
        !           432: 
        !           433:        /* Construct data-out descriptor, if present */
        !           434:        if ( command->data_out ) {
        !           435:                cmd->data_buffer_formats |= SRP_CMD_DO_FMT_DIRECT;
        !           436:                data_out = iob_put ( iobuf, sizeof ( *data_out ) );
        !           437:                data_out->address =
        !           438:                    cpu_to_be64 ( user_to_phys ( command->data_out, 0 ) );
        !           439:                data_out->handle = ntohl ( srpdev->memory_handle );
        !           440:                data_out->len = ntohl ( command->data_out_len );
        !           441:        }
        !           442: 
        !           443:        /* Construct data-in descriptor, if present */
        !           444:        if ( command->data_in ) {
        !           445:                cmd->data_buffer_formats |= SRP_CMD_DI_FMT_DIRECT;
        !           446:                data_in = iob_put ( iobuf, sizeof ( *data_in ) );
        !           447:                data_in->address =
        !           448:                     cpu_to_be64 ( user_to_phys ( command->data_in, 0 ) );
        !           449:                data_in->handle = ntohl ( srpdev->memory_handle );
        !           450:                data_in->len = ntohl ( command->data_in_len );
        !           451:        }
        !           452: 
        !           453:        DBGC2 ( srpdev, "SRP %p tag %08x CMD " SCSI_CDB_FORMAT "\n",
        !           454:                srpdev, tag, SCSI_CDB_DATA ( cmd->cdb ) );
        !           455: 
        !           456:        /* Send IU */
        !           457:        if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) {
        !           458:                DBGC ( srpdev, "SRP %p tag %08x could not send CMD: %s\n",
        !           459:                       srpdev, tag, strerror ( rc ) );
        !           460:                return rc;
        !           461:        }
        !           462: 
        !           463:        return 0;
        !           464: }
        !           465: 
        !           466: /**
        !           467:  * Receive SRP SCSI response
        !           468:  *
        !           469:  * @v srpdev           SRP device
        !           470:  * @v data             SRP IU
        !           471:  * @v len              Length of SRP IU
        !           472:  * @ret rc             Returns status code
        !           473:  */
        !           474: static int srp_rsp ( struct srp_device *srpdev,
        !           475:                     const void *data, size_t len ) {
        !           476:        const struct srp_rsp *rsp = data;
        !           477:        struct srp_command *srpcmd;
        !           478:        struct scsi_rsp response;
        !           479:        const void *sense;
        !           480:        ssize_t data_out_residual_count;
        !           481:        ssize_t data_in_residual_count;
        !           482: 
        !           483:        /* Sanity check */
        !           484:        if ( len < sizeof ( *rsp ) ) {
        !           485:                DBGC ( srpdev, "SRP %p RSP too short (%zd bytes)\n",
        !           486:                       srpdev, len );
        !           487:                return -EINVAL;
        !           488:        }
        !           489:        DBGC2 ( srpdev, "SRP %p tag %08x RSP stat %02x dores %08x dires "
        !           490:                "%08x valid %02x%s%s%s%s%s%s\n",
        !           491:                srpdev, ntohl ( rsp->tag.dwords[1] ), rsp->status,
        !           492:                ntohl ( rsp->data_out_residual_count ),
        !           493:                ntohl ( rsp->data_in_residual_count ), rsp->valid,
        !           494:                ( ( rsp->valid & SRP_RSP_VALID_DIUNDER ) ? " diunder" : "" ),
        !           495:                ( ( rsp->valid & SRP_RSP_VALID_DIOVER ) ? " diover" : "" ),
        !           496:                ( ( rsp->valid & SRP_RSP_VALID_DOUNDER ) ? " dounder" : "" ),
        !           497:                ( ( rsp->valid & SRP_RSP_VALID_DOOVER ) ? " doover" : "" ),
        !           498:                ( ( rsp->valid & SRP_RSP_VALID_SNSVALID ) ? " sns" : "" ),
        !           499:                ( ( rsp->valid & SRP_RSP_VALID_RSPVALID ) ? " rsp" : "" ) );
        !           500: 
        !           501:        /* Identify command by tag */
        !           502:        srpcmd = srp_find_tag ( srpdev, ntohl ( rsp->tag.dwords[1] ) );
        !           503:        if ( ! srpcmd ) {
        !           504:                DBGC ( srpdev, "SRP %p tag %08x unrecognised RSP\n",
        !           505:                       srpdev, ntohl ( rsp->tag.dwords[1] ) );
        !           506:                return -ENOENT;
        !           507:        }
        !           508: 
        !           509:        /* Hold command reference for remainder of function */
        !           510:        srpcmd_get ( srpcmd );
        !           511: 
        !           512:        /* Build SCSI response */
        !           513:        memset ( &response, 0, sizeof ( response ) );
        !           514:        response.status = rsp->status;
        !           515:        data_out_residual_count = ntohl ( rsp->data_out_residual_count );
        !           516:        data_in_residual_count = ntohl ( rsp->data_in_residual_count );
        !           517:        if ( rsp->valid & SRP_RSP_VALID_DOOVER ) {
        !           518:                response.overrun = data_out_residual_count;
        !           519:        } else if ( rsp->valid & SRP_RSP_VALID_DOUNDER ) {
        !           520:                response.overrun = -(data_out_residual_count);
        !           521:        } else if ( rsp->valid & SRP_RSP_VALID_DIOVER ) {
        !           522:                response.overrun = data_in_residual_count;
        !           523:        } else if ( rsp->valid & SRP_RSP_VALID_DIUNDER ) {
        !           524:                response.overrun = -(data_in_residual_count);
        !           525:        }
        !           526:        sense = srp_rsp_sense_data ( rsp );
        !           527:        if ( sense )
        !           528:                memcpy ( &response.sense, sense, sizeof ( response.sense ) );
        !           529: 
        !           530:        /* Report SCSI response */
        !           531:        scsi_response ( &srpcmd->scsi, &response );
        !           532: 
        !           533:        /* Close SCSI command */
        !           534:        srpcmd_close ( srpcmd, 0 );
        !           535: 
        !           536:        /* Drop temporary command reference */
        !           537:        srpcmd_put ( srpcmd );
        !           538: 
        !           539:        return 0;
        !           540: }
        !           541: 
        !           542: /**
        !           543:  * Receive SRP unrecognised response IU
        !           544:  *
        !           545:  * @v srpdev           SRP device
        !           546:  * @v data             SRP IU
        !           547:  * @v len              Length of SRP IU
        !           548:  * @ret rc             Returns status code
        !           549:  */
        !           550: static int srp_unrecognised ( struct srp_device *srpdev,
        !           551:                              const void *data, size_t len ) {
        !           552:        const struct srp_common *common = data;
        !           553: 
        !           554:        DBGC ( srpdev, "SRP %p tag %08x unrecognised IU type %02x:\n",
        !           555:               srpdev, ntohl ( common->tag.dwords[1] ), common->type );
        !           556:        DBGC_HDA ( srpdev, 0, data, len );
        !           557: 
        !           558:        return -ENOTSUP;
        !           559: }
        !           560: 
        !           561: /** SRP command SCSI interface operations */
        !           562: static struct interface_operation srpcmd_scsi_op[] = {
        !           563:        INTF_OP ( intf_close, struct srp_command *, srpcmd_close ),
        !           564: };
        !           565: 
        !           566: /** SRP command SCSI interface descriptor */
        !           567: static struct interface_descriptor srpcmd_scsi_desc =
        !           568:        INTF_DESC ( struct srp_command, scsi, srpcmd_scsi_op );
        !           569: 
        !           570: /**
        !           571:  * Issue SRP SCSI command
        !           572:  *
        !           573:  * @v srpdev           SRP device
        !           574:  * @v parent           Parent interface
        !           575:  * @v command          SCSI command
        !           576:  * @ret tag            Command tag, or negative error
        !           577:  */
        !           578: static int srpdev_scsi_command ( struct srp_device *srpdev,
        !           579:                                 struct interface *parent,
        !           580:                                 struct scsi_cmd *command ) {
        !           581:        struct srp_command *srpcmd;
        !           582:        int tag;
        !           583:        int rc;
        !           584: 
        !           585:        /* Allocate command tag */
        !           586:        tag = srp_new_tag ( srpdev );
        !           587:        if ( tag < 0 ) {
        !           588:                rc = tag;
        !           589:                goto err_tag;
        !           590:        }
        !           591: 
        !           592:        /* Allocate and initialise structure */
        !           593:        srpcmd = zalloc ( sizeof ( *srpcmd ) );
        !           594:        if ( ! srpcmd ) {
        !           595:                rc = -ENOMEM;
        !           596:                goto err_zalloc;
        !           597:        }
        !           598:        ref_init ( &srpcmd->refcnt, srpcmd_free );
        !           599:        intf_init ( &srpcmd->scsi, &srpcmd_scsi_desc, &srpcmd->refcnt );
        !           600:        srpcmd->srpdev = srpdev_get ( srpdev );
        !           601:        list_add ( &srpcmd->list, &srpdev->commands );
        !           602:        srpcmd->tag = tag;
        !           603: 
        !           604:        /* Send command IU */
        !           605:        if ( ( rc = srp_cmd ( srpdev, command, srpcmd->tag ) ) != 0 )
        !           606:                goto err_cmd;
        !           607: 
        !           608:        /* Attach to parent interface, leave reference with command
        !           609:         * list, and return.
        !           610:         */
        !           611:        intf_plug_plug ( &srpcmd->scsi, parent );
        !           612:        return srpcmd->tag;
        !           613: 
        !           614:  err_cmd:
        !           615:        srpcmd_close ( srpcmd, rc );
        !           616:  err_zalloc:
        !           617:  err_tag:
        !           618:        return rc;
        !           619: }
        !           620: 
        !           621: /**
        !           622:  * Receive data from SRP socket
        !           623:  *
        !           624:  * @v srpdev           SRP device
        !           625:  * @v iobuf            Datagram I/O buffer
        !           626:  * @v meta             Data transfer metadata
        !           627:  * @ret rc             Return status code
        !           628:  */
        !           629: static int srpdev_deliver ( struct srp_device *srpdev,
        !           630:                            struct io_buffer *iobuf,
        !           631:                            struct xfer_metadata *meta __unused ) {
        !           632:        struct srp_common *common = iobuf->data;
        !           633:        int ( * type ) ( struct srp_device *srp, const void *data, size_t len );
        !           634:        int rc;
        !           635: 
        !           636:        /* Sanity check */
        !           637:        if ( iob_len ( iobuf ) < sizeof ( *common ) ) {
        !           638:                DBGC ( srpdev, "SRP %p IU too short (%zd bytes)\n",
        !           639:                       srpdev, iob_len ( iobuf ) );
        !           640:                rc = -EINVAL;
        !           641:                goto err;
        !           642:        }
        !           643: 
        !           644:        /* Determine IU type */
        !           645:        switch ( common->type ) {
        !           646:        case SRP_LOGIN_RSP:
        !           647:                type = srp_login_rsp;
        !           648:                break;
        !           649:        case SRP_LOGIN_REJ:
        !           650:                type = srp_login_rej;
        !           651:                break;
        !           652:        case SRP_RSP:
        !           653:                type = srp_rsp;
        !           654:                break;
        !           655:        default:
        !           656:                type = srp_unrecognised;
        !           657:                break;
        !           658:        }
        !           659: 
        !           660:        /* Handle IU */
        !           661:        if ( ( rc = type ( srpdev, iobuf->data, iob_len ( iobuf ) ) ) != 0 )
        !           662:                goto err;
        !           663: 
        !           664:        free_iob ( iobuf );
        !           665:        return 0;
        !           666: 
        !           667:  err:
        !           668:        DBGC ( srpdev, "SRP %p closing due to received IU (%s):\n",
        !           669:               srpdev, strerror ( rc ) );
        !           670:        DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) );
        !           671:        free_iob ( iobuf );
        !           672:        srpdev_close ( srpdev, rc );
        !           673:        return rc;
        !           674: }
        !           675: 
        !           676: /**
        !           677:  * Check SRP device flow-control window
        !           678:  *
        !           679:  * @v srpdev           SRP device
        !           680:  * @ret len            Length of window
        !           681:  */
        !           682: static size_t srpdev_window ( struct srp_device *srpdev ) {
        !           683:        return ( srpdev->logged_in ? ~( ( size_t ) 0 ) : 0 );
        !           684: }
        !           685: 
        !           686: /**
        !           687:  * A (transport-independent) sBFT created by iPXE
        !           688:  */
        !           689: struct ipxe_sbft {
        !           690:        /** The table header */
        !           691:        struct sbft_table table;
        !           692:        /** The SCSI subtable */
        !           693:        struct sbft_scsi_subtable scsi;
        !           694:        /** The SRP subtable */
        !           695:        struct sbft_srp_subtable srp;
        !           696: } __attribute__ (( packed, aligned ( 16 ) ));
        !           697: 
        !           698: /**
        !           699:  * Describe SRP device in an ACPI table
        !           700:  *
        !           701:  * @v srpdev           SRP device
        !           702:  * @v acpi             ACPI table
        !           703:  * @v len              Length of ACPI table
        !           704:  * @ret rc             Return status code
        !           705:  */
        !           706: static int srpdev_describe ( struct srp_device *srpdev,
        !           707:                             struct acpi_description_header *acpi,
        !           708:                             size_t len ) {
        !           709:        struct ipxe_sbft *sbft =
        !           710:                container_of ( acpi, struct ipxe_sbft, table.acpi );
        !           711:        int rc;
        !           712: 
        !           713:        /* Sanity check */
        !           714:        if ( len < sizeof ( *sbft ) )
        !           715:                return -ENOBUFS;
        !           716: 
        !           717:        /* Populate table */
        !           718:        sbft->table.acpi.signature = cpu_to_le32 ( SBFT_SIG );
        !           719:        sbft->table.acpi.length = cpu_to_le32 ( sizeof ( *sbft ) );
        !           720:        sbft->table.acpi.revision = 1;
        !           721:        sbft->table.scsi_offset =
        !           722:                cpu_to_le16 ( offsetof ( typeof ( *sbft ), scsi ) );
        !           723:        memcpy ( &sbft->scsi.lun, &srpdev->lun, sizeof ( sbft->scsi.lun ) );
        !           724:        sbft->table.srp_offset =
        !           725:                cpu_to_le16 ( offsetof ( typeof ( *sbft ), srp ) );
        !           726:        memcpy ( &sbft->srp.initiator, &srpdev->initiator,
        !           727:                 sizeof ( sbft->srp.initiator ) );
        !           728:        memcpy ( &sbft->srp.target, &srpdev->target,
        !           729:                 sizeof ( sbft->srp.target ) );
        !           730: 
        !           731:        /* Ask transport layer to describe transport-specific portions */
        !           732:        if ( ( rc = acpi_describe ( &srpdev->socket, acpi, len ) ) != 0 ) {
        !           733:                DBGC ( srpdev, "SRP %p cannot describe transport layer: %s\n",
        !           734:                       srpdev, strerror ( rc ) );
        !           735:                return rc;
        !           736:        }
        !           737: 
        !           738:        return 0;
        !           739: }
        !           740: 
        !           741: /** SRP device socket interface operations */
        !           742: static struct interface_operation srpdev_socket_op[] = {
        !           743:        INTF_OP ( xfer_deliver, struct srp_device *, srpdev_deliver ),
        !           744:        INTF_OP ( intf_close, struct srp_device *, srpdev_close ),
        !           745: };
        !           746: 
        !           747: /** SRP device socket interface descriptor */
        !           748: static struct interface_descriptor srpdev_socket_desc =
        !           749:        INTF_DESC_PASSTHRU ( struct srp_device, socket, srpdev_socket_op,
        !           750:                             scsi );
        !           751: 
        !           752: /** SRP device SCSI interface operations */
        !           753: static struct interface_operation srpdev_scsi_op[] = {
        !           754:        INTF_OP ( scsi_command, struct srp_device *, srpdev_scsi_command ),
        !           755:        INTF_OP ( xfer_window, struct srp_device *, srpdev_window ),
        !           756:        INTF_OP ( intf_close, struct srp_device *, srpdev_close ),
        !           757:        INTF_OP ( acpi_describe, struct srp_device *, srpdev_describe ),
        !           758: };
        !           759: 
        !           760: /** SRP device SCSI interface descriptor */
        !           761: static struct interface_descriptor srpdev_scsi_desc =
        !           762:        INTF_DESC_PASSTHRU ( struct srp_device, scsi, srpdev_scsi_op, socket  );
        !           763: 
        !           764: /**
        !           765:  * Open SRP device
        !           766:  *
        !           767:  * @v block            Block control interface
        !           768:  * @v socket           Socket interface
        !           769:  * @v initiator                Initiator port ID
        !           770:  * @v target           Target port ID
        !           771:  * @v memory_handle    RDMA memory handle
        !           772:  * @v lun              SCSI LUN
        !           773:  * @ret rc             Return status code
        !           774:  */
        !           775: int srp_open ( struct interface *block, struct interface *socket,
        !           776:               union srp_port_id *initiator, union srp_port_id *target,
        !           777:               uint32_t memory_handle, struct scsi_lun *lun ) {
        !           778:        struct srp_device *srpdev;
        !           779:        int tag;
        !           780:        int rc;
        !           781: 
        !           782:        /* Allocate and initialise structure */
        !           783:        srpdev = zalloc ( sizeof ( *srpdev ) );
        !           784:        if ( ! srpdev ) {
        !           785:                rc = -ENOMEM;
        !           786:                goto err_zalloc;
        !           787:        }
        !           788:        ref_init ( &srpdev->refcnt, NULL );
        !           789:        intf_init ( &srpdev->scsi, &srpdev_scsi_desc, &srpdev->refcnt );
        !           790:        intf_init ( &srpdev->socket, &srpdev_socket_desc, &srpdev->refcnt );
        !           791:        INIT_LIST_HEAD ( &srpdev->commands );
        !           792:        srpdev->memory_handle = memory_handle;
        !           793:        DBGC ( srpdev, "SRP %p %08x%08x%08x%08x->%08x%08x%08x%08x\n", srpdev,
        !           794:               ntohl ( initiator->dwords[0] ), ntohl ( initiator->dwords[1] ),
        !           795:               ntohl ( initiator->dwords[2] ), ntohl ( initiator->dwords[3] ),
        !           796:               ntohl ( target->dwords[0] ), ntohl ( target->dwords[1] ),
        !           797:               ntohl ( target->dwords[2] ), ntohl ( target->dwords[3] ) );
        !           798: 
        !           799:        /* Preserve parameters required for boot firmware table */
        !           800:        memcpy ( &srpdev->initiator, initiator, sizeof ( srpdev->initiator ) );
        !           801:        memcpy ( &srpdev->target, target, sizeof ( srpdev->target ) );
        !           802:        memcpy ( &srpdev->lun, lun, sizeof ( srpdev->lun ) );
        !           803: 
        !           804:        /* Attach to socket interface and initiate login */
        !           805:        intf_plug_plug ( &srpdev->socket, socket );
        !           806:        tag = srp_new_tag ( srpdev );
        !           807:        assert ( tag >= 0 ); /* Cannot fail when no commands in progress */
        !           808:        if ( ( rc = srp_login ( srpdev, initiator, target, tag ) ) != 0 )
        !           809:                goto err_login;
        !           810: 
        !           811:        /* Attach SCSI device to parent interface */
        !           812:        if ( ( rc = scsi_open ( block, &srpdev->scsi, lun ) ) != 0 ) {
        !           813:                DBGC ( srpdev, "SRP %p could not create SCSI device: %s\n",
        !           814:                       srpdev, strerror ( rc ) );
        !           815:                goto err_scsi_open;
        !           816:        }
        !           817: 
        !           818:        /* Mortalise self and return */
        !           819:        ref_put ( &srpdev->refcnt );
        !           820:        return 0;
        !           821: 
        !           822:  err_scsi_open:
        !           823:  err_login:
        !           824:        srpdev_close ( srpdev, rc );
        !           825:        ref_put ( &srpdev->refcnt );
        !           826:  err_zalloc:
        !           827:        return rc;
        !           828: }

unix.superglobalmegacorp.com

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