Annotation of qemu/roms/ipxe/src/drivers/block/srp.c, revision 1.1.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.