Annotation of qemu/roms/ipxe/src/net/aoe.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (C) 2006 Michael Brown <[email protected]>.
        !             3:  *
        !             4:  * This program is free software; you can redistribute it and/or
        !             5:  * modify it under the terms of the GNU General Public License as
        !             6:  * published by the Free Software Foundation; either version 2 of the
        !             7:  * License, or any later version.
        !             8:  *
        !             9:  * This program is distributed in the hope that it will be useful, but
        !            10:  * WITHOUT ANY WARRANTY; without even the implied warranty of
        !            11:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            12:  * General Public License for more details.
        !            13:  *
        !            14:  * You should have received a copy of the GNU General Public License
        !            15:  * along with this program; if not, write to the Free Software
        !            16:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
        !            17:  */
        !            18: 
        !            19: FILE_LICENCE ( GPL2_OR_LATER );
        !            20: 
        !            21: #include <stddef.h>
        !            22: #include <string.h>
        !            23: #include <stdio.h>
        !            24: #include <stdlib.h>
        !            25: #include <errno.h>
        !            26: #include <assert.h>
        !            27: #include <byteswap.h>
        !            28: #include <ipxe/list.h>
        !            29: #include <ipxe/if_ether.h>
        !            30: #include <ipxe/iobuf.h>
        !            31: #include <ipxe/uaccess.h>
        !            32: #include <ipxe/netdevice.h>
        !            33: #include <ipxe/features.h>
        !            34: #include <ipxe/interface.h>
        !            35: #include <ipxe/xfer.h>
        !            36: #include <ipxe/uri.h>
        !            37: #include <ipxe/open.h>
        !            38: #include <ipxe/ata.h>
        !            39: #include <ipxe/device.h>
        !            40: #include <ipxe/aoe.h>
        !            41: 
        !            42: /** @file
        !            43:  *
        !            44:  * AoE protocol
        !            45:  *
        !            46:  */
        !            47: 
        !            48: FEATURE ( FEATURE_PROTOCOL, "AoE", DHCP_EB_FEATURE_AOE, 1 );
        !            49: 
        !            50: struct net_protocol aoe_protocol __net_protocol;
        !            51: 
        !            52: /******************************************************************************
        !            53:  *
        !            54:  * AoE devices and commands
        !            55:  *
        !            56:  ******************************************************************************
        !            57:  */
        !            58: 
        !            59: /** List of all AoE devices */
        !            60: static LIST_HEAD ( aoe_devices );
        !            61: 
        !            62: /** List of active AoE commands */
        !            63: static LIST_HEAD ( aoe_commands );
        !            64: 
        !            65: /** An AoE device */
        !            66: struct aoe_device {
        !            67:        /** Reference counter */
        !            68:        struct refcnt refcnt;
        !            69: 
        !            70:        /** Network device */
        !            71:        struct net_device *netdev;
        !            72:        /** ATA command issuing interface */
        !            73:        struct interface ata;
        !            74: 
        !            75:        /** Major number */
        !            76:        uint16_t major;
        !            77:        /** Minor number */
        !            78:        uint8_t minor;
        !            79:        /** Target MAC address */
        !            80:        uint8_t target[MAX_LL_ADDR_LEN];
        !            81: 
        !            82:        /** Saved timeout value */
        !            83:        unsigned long timeout;
        !            84: 
        !            85:        /** Configuration command interface */
        !            86:        struct interface config;
        !            87:        /** Device is configued */
        !            88:        int configured;
        !            89: };
        !            90: 
        !            91: /** An AoE command */
        !            92: struct aoe_command {
        !            93:        /** Reference count */
        !            94:        struct refcnt refcnt;
        !            95:        /** AOE device */
        !            96:        struct aoe_device *aoedev;
        !            97:        /** List of active commands */
        !            98:        struct list_head list;
        !            99: 
        !           100:        /** ATA command interface */
        !           101:        struct interface ata;
        !           102: 
        !           103:        /** ATA command */
        !           104:        struct ata_cmd command;
        !           105:        /** Command type */
        !           106:        struct aoe_command_type *type;
        !           107:        /** Command tag */
        !           108:        uint32_t tag;
        !           109: 
        !           110:        /** Retransmission timer */
        !           111:        struct retry_timer timer;
        !           112: };
        !           113: 
        !           114: /** An AoE command type */
        !           115: struct aoe_command_type {
        !           116:        /**
        !           117:         * Calculate length of AoE command IU
        !           118:         *
        !           119:         * @v aoecmd            AoE command
        !           120:         * @ret len             Length of command IU
        !           121:         */
        !           122:        size_t ( * cmd_len ) ( struct aoe_command *aoecmd );
        !           123:        /**
        !           124:         * Build AoE command IU
        !           125:         *
        !           126:         * @v aoecmd            AoE command
        !           127:         * @v data              Command IU
        !           128:         * @v len               Length of command IU
        !           129:         */
        !           130:        void ( * cmd ) ( struct aoe_command *aoecmd, void *data, size_t len );
        !           131:        /**
        !           132:         * Handle AoE response IU
        !           133:         *
        !           134:         * @v aoecmd            AoE command
        !           135:         * @v data              Response IU
        !           136:         * @v len               Length of response IU
        !           137:         * @v ll_source         Link-layer source address
        !           138:         * @ret rc              Return status code
        !           139:         */
        !           140:        int ( * rsp ) ( struct aoe_command *aoecmd, const void *data,
        !           141:                        size_t len, const void *ll_source );
        !           142: };
        !           143: 
        !           144: /**
        !           145:  * Get reference to AoE device
        !           146:  *
        !           147:  * @v aoedev           AoE device
        !           148:  * @ret aoedev         AoE device
        !           149:  */
        !           150: static inline __attribute__ (( always_inline )) struct aoe_device *
        !           151: aoedev_get ( struct aoe_device *aoedev ) {
        !           152:        ref_get ( &aoedev->refcnt );
        !           153:        return aoedev;
        !           154: }
        !           155: 
        !           156: /**
        !           157:  * Drop reference to AoE device
        !           158:  *
        !           159:  * @v aoedev           AoE device
        !           160:  */
        !           161: static inline __attribute__ (( always_inline )) void
        !           162: aoedev_put ( struct aoe_device *aoedev ) {
        !           163:        ref_put ( &aoedev->refcnt );
        !           164: }
        !           165: 
        !           166: /**
        !           167:  * Get reference to AoE command
        !           168:  *
        !           169:  * @v aoecmd           AoE command
        !           170:  * @ret aoecmd         AoE command
        !           171:  */
        !           172: static inline __attribute__ (( always_inline )) struct aoe_command *
        !           173: aoecmd_get ( struct aoe_command *aoecmd ) {
        !           174:        ref_get ( &aoecmd->refcnt );
        !           175:        return aoecmd;
        !           176: }
        !           177: 
        !           178: /**
        !           179:  * Drop reference to AoE command
        !           180:  *
        !           181:  * @v aoecmd           AoE command
        !           182:  */
        !           183: static inline __attribute__ (( always_inline )) void
        !           184: aoecmd_put ( struct aoe_command *aoecmd ) {
        !           185:        ref_put ( &aoecmd->refcnt );
        !           186: }
        !           187: 
        !           188: /**
        !           189:  * Name AoE device
        !           190:  *
        !           191:  * @v aoedev           AoE device
        !           192:  * @ret name           AoE device name
        !           193:  */
        !           194: static const char * aoedev_name ( struct aoe_device *aoedev ) {
        !           195:        static char buf[16];
        !           196: 
        !           197:        snprintf ( buf, sizeof ( buf ), "%s/e%d.%d", aoedev->netdev->name,
        !           198:                   aoedev->major, aoedev->minor );
        !           199:        return buf;
        !           200: }
        !           201: 
        !           202: /**
        !           203:  * Free AoE command
        !           204:  *
        !           205:  * @v refcnt           Reference counter
        !           206:  */
        !           207: static void aoecmd_free ( struct refcnt *refcnt ) {
        !           208:        struct aoe_command *aoecmd =
        !           209:                container_of ( refcnt, struct aoe_command, refcnt );
        !           210: 
        !           211:        assert ( ! timer_running ( &aoecmd->timer ) );
        !           212:        assert ( list_empty ( &aoecmd->list ) );
        !           213: 
        !           214:        aoedev_put ( aoecmd->aoedev );
        !           215:        free ( aoecmd );
        !           216: }
        !           217: 
        !           218: /**
        !           219:  * Close AoE command
        !           220:  *
        !           221:  * @v aoecmd           AoE command
        !           222:  * @v rc               Reason for close
        !           223:  */
        !           224: static void aoecmd_close ( struct aoe_command *aoecmd, int rc ) {
        !           225:        struct aoe_device *aoedev = aoecmd->aoedev;
        !           226: 
        !           227:        /* Stop timer */
        !           228:        stop_timer ( &aoecmd->timer );
        !           229: 
        !           230:        /* Preserve the timeout value for subsequent commands */
        !           231:        aoedev->timeout = aoecmd->timer.timeout;
        !           232: 
        !           233:        /* Remove from list of commands */
        !           234:        if ( ! list_empty ( &aoecmd->list ) ) {
        !           235:                list_del ( &aoecmd->list );
        !           236:                INIT_LIST_HEAD ( &aoecmd->list );
        !           237:                aoecmd_put ( aoecmd );
        !           238:        }
        !           239: 
        !           240:        /* Shut down interfaces */
        !           241:        intf_shutdown ( &aoecmd->ata, rc );
        !           242: }
        !           243: 
        !           244: /**
        !           245:  * Transmit AoE command request
        !           246:  *
        !           247:  * @v aoecmd           AoE command
        !           248:  * @ret rc             Return status code
        !           249:  */
        !           250: static int aoecmd_tx ( struct aoe_command *aoecmd ) {
        !           251:        struct aoe_device *aoedev = aoecmd->aoedev;
        !           252:        struct net_device *netdev = aoedev->netdev;
        !           253:        struct io_buffer *iobuf;
        !           254:        struct aoehdr *aoehdr;
        !           255:        size_t cmd_len;
        !           256:        int rc;
        !           257: 
        !           258:        /* Sanity check */
        !           259:        assert ( netdev != NULL );
        !           260: 
        !           261:        /* If we are transmitting anything that requires a response,
        !           262:          * start the retransmission timer.  Do this before attempting
        !           263:          * to allocate the I/O buffer, in case allocation itself
        !           264:          * fails.
        !           265:          */
        !           266:        start_timer ( &aoecmd->timer );
        !           267: 
        !           268:        /* Create outgoing I/O buffer */
        !           269:        cmd_len = aoecmd->type->cmd_len ( aoecmd );
        !           270:        iobuf = alloc_iob ( MAX_LL_HEADER_LEN + cmd_len );
        !           271:        if ( ! iobuf )
        !           272:                return -ENOMEM;
        !           273:        iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
        !           274:        aoehdr = iob_put ( iobuf, cmd_len );
        !           275: 
        !           276:        /* Fill AoE header */
        !           277:        memset ( aoehdr, 0, sizeof ( *aoehdr ) );
        !           278:        aoehdr->ver_flags = AOE_VERSION;
        !           279:        aoehdr->major = htons ( aoedev->major );
        !           280:        aoehdr->minor = aoedev->minor;
        !           281:        aoehdr->tag = htonl ( aoecmd->tag );
        !           282:        aoecmd->type->cmd ( aoecmd, iobuf->data, iob_len ( iobuf ) );
        !           283: 
        !           284:        /* Send packet */
        !           285:        if ( ( rc = net_tx ( iobuf, netdev, &aoe_protocol, aoedev->target,
        !           286:                             netdev->ll_addr ) ) != 0 ) {
        !           287:                DBGC ( aoedev, "AoE %s/%08x could not transmit: %s\n",
        !           288:                       aoedev_name ( aoedev ), aoecmd->tag,
        !           289:                       strerror ( rc ) );
        !           290:                return rc;
        !           291:        }
        !           292: 
        !           293:        return 0;
        !           294: }
        !           295: 
        !           296: /**
        !           297:  * Receive AoE command response
        !           298:  *
        !           299:  * @v aoecmd           AoE command
        !           300:  * @v iobuf            I/O buffer
        !           301:  * @v ll_source                Link-layer source address
        !           302:  * @ret rc             Return status code
        !           303:  */
        !           304: static int aoecmd_rx ( struct aoe_command *aoecmd, struct io_buffer *iobuf,
        !           305:                       const void *ll_source ) {
        !           306:        struct aoe_device *aoedev = aoecmd->aoedev;
        !           307:        struct aoehdr *aoehdr = iobuf->data;
        !           308:        int rc;
        !           309: 
        !           310:        /* Sanity check */
        !           311:        if ( iob_len ( iobuf ) < sizeof ( *aoehdr ) ) {
        !           312:                DBGC ( aoedev, "AoE %s/%08x received underlength response "
        !           313:                       "(%zd bytes)\n", aoedev_name ( aoedev ),
        !           314:                       aoecmd->tag, iob_len ( iobuf ) );
        !           315:                rc = -EINVAL;
        !           316:                goto done;
        !           317:        }
        !           318:        if ( ( ntohs ( aoehdr->major ) != aoedev->major ) ||
        !           319:             ( aoehdr->minor != aoedev->minor ) ) {
        !           320:                DBGC ( aoedev, "AoE %s/%08x received response for incorrect "
        !           321:                       "device e%d.%d\n", aoedev_name ( aoedev ), aoecmd->tag,
        !           322:                       ntohs ( aoehdr->major ), aoehdr->minor );
        !           323:                rc = -EINVAL;
        !           324:                goto done;
        !           325:        }
        !           326: 
        !           327:        /* Catch command failures */
        !           328:        if ( aoehdr->ver_flags & AOE_FL_ERROR ) {
        !           329:                DBGC ( aoedev, "AoE %s/%08x terminated in error\n",
        !           330:                       aoedev_name ( aoedev ), aoecmd->tag );
        !           331:                aoecmd_close ( aoecmd, -EIO );
        !           332:                rc = -EIO;
        !           333:                goto done;
        !           334:        }
        !           335: 
        !           336:        /* Hand off to command completion handler */
        !           337:        if ( ( rc = aoecmd->type->rsp ( aoecmd, iobuf->data, iob_len ( iobuf ),
        !           338:                                        ll_source ) ) != 0 )
        !           339:                goto done;
        !           340: 
        !           341:  done:
        !           342:        /* Free I/O buffer */
        !           343:        free_iob ( iobuf );
        !           344: 
        !           345:        /* Terminate command */
        !           346:        aoecmd_close ( aoecmd, rc );
        !           347: 
        !           348:        return rc;
        !           349: }
        !           350: 
        !           351: /**
        !           352:  * Handle AoE retry timer expiry
        !           353:  *
        !           354:  * @v timer            AoE retry timer
        !           355:  * @v fail             Failure indicator
        !           356:  */
        !           357: static void aoecmd_expired ( struct retry_timer *timer, int fail ) {
        !           358:        struct aoe_command *aoecmd =
        !           359:                container_of ( timer, struct aoe_command, timer );
        !           360: 
        !           361:        if ( fail ) {
        !           362:                aoecmd_close ( aoecmd, -ETIMEDOUT );
        !           363:        } else {
        !           364:                aoecmd_tx ( aoecmd );
        !           365:        }
        !           366: }
        !           367: 
        !           368: /**
        !           369:  * Calculate length of AoE ATA command IU
        !           370:  *
        !           371:  * @v aoecmd           AoE command
        !           372:  * @ret len            Length of command IU
        !           373:  */
        !           374: static size_t aoecmd_ata_cmd_len ( struct aoe_command *aoecmd ) {
        !           375:        struct ata_cmd *command = &aoecmd->command;
        !           376: 
        !           377:        return ( sizeof ( struct aoehdr ) + sizeof ( struct aoeata ) +
        !           378:                 command->data_out_len );
        !           379: }
        !           380: 
        !           381: /**
        !           382:  * Build AoE ATA command IU
        !           383:  *
        !           384:  * @v aoecmd           AoE command
        !           385:  * @v data             Command IU
        !           386:  * @v len              Length of command IU
        !           387:  */
        !           388: static void aoecmd_ata_cmd ( struct aoe_command *aoecmd,
        !           389:                             void *data, size_t len ) {
        !           390:        struct aoe_device *aoedev = aoecmd->aoedev;
        !           391:        struct ata_cmd *command = &aoecmd->command;
        !           392:        struct aoehdr *aoehdr = data;
        !           393:        struct aoeata *aoeata = &aoehdr->payload[0].ata;
        !           394: 
        !           395:        /* Sanity check */
        !           396:        linker_assert ( AOE_FL_DEV_HEAD == ATA_DEV_SLAVE, __fix_ata_h__ );
        !           397:        assert ( len == ( sizeof ( *aoehdr ) + sizeof ( *aoeata ) +
        !           398:                          command->data_out_len ) );
        !           399: 
        !           400:        /* Build IU */
        !           401:        aoehdr->command = AOE_CMD_ATA;
        !           402:        memset ( aoeata, 0, sizeof ( *aoeata ) );
        !           403:        aoeata->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 ) |
        !           404:                           ( command->cb.device & ATA_DEV_SLAVE ) |
        !           405:                           ( command->data_out_len ? AOE_FL_WRITE : 0 ) );
        !           406:        aoeata->err_feat = command->cb.err_feat.bytes.cur;
        !           407:        aoeata->count = command->cb.count.native;
        !           408:        aoeata->cmd_stat = command->cb.cmd_stat;
        !           409:        aoeata->lba.u64 = cpu_to_le64 ( command->cb.lba.native );
        !           410:        if ( ! command->cb.lba48 )
        !           411:                aoeata->lba.bytes[3] |=
        !           412:                        ( command->cb.device & ATA_DEV_MASK );
        !           413:        copy_from_user ( aoeata->data, command->data_out, 0,
        !           414:                         command->data_out_len );
        !           415: 
        !           416:        DBGC2 ( aoedev, "AoE %s/%08x ATA cmd %02x:%02x:%02x:%02x:%08llx",
        !           417:                aoedev_name ( aoedev ), aoecmd->tag, aoeata->aflags,
        !           418:                aoeata->err_feat, aoeata->count, aoeata->cmd_stat,
        !           419:                aoeata->lba.u64 );
        !           420:        if ( command->data_out_len )
        !           421:                DBGC2 ( aoedev, " out %04zx", command->data_out_len );
        !           422:        if ( command->data_in_len )
        !           423:                DBGC2 ( aoedev, " in %04zx", command->data_in_len );
        !           424:        DBGC2 ( aoedev, "\n" );
        !           425: }
        !           426: 
        !           427: /**
        !           428:  * Handle AoE ATA response IU
        !           429:  *
        !           430:  * @v aoecmd           AoE command
        !           431:  * @v data             Response IU
        !           432:  * @v len              Length of response IU
        !           433:  * @v ll_source                Link-layer source address
        !           434:  * @ret rc             Return status code
        !           435:  */
        !           436: static int aoecmd_ata_rsp ( struct aoe_command *aoecmd, const void *data,
        !           437:                            size_t len, const void *ll_source __unused ) {
        !           438:        struct aoe_device *aoedev = aoecmd->aoedev;
        !           439:        struct ata_cmd *command = &aoecmd->command;
        !           440:        const struct aoehdr *aoehdr = data;
        !           441:        const struct aoeata *aoeata = &aoehdr->payload[0].ata;
        !           442:        size_t data_len;
        !           443: 
        !           444:        /* Sanity check */
        !           445:        if ( len < ( sizeof ( *aoehdr ) + sizeof ( *aoeata ) ) ) {
        !           446:                DBGC ( aoedev, "AoE %s/%08x received underlength ATA response "
        !           447:                       "(%zd bytes)\n", aoedev_name ( aoedev ),
        !           448:                       aoecmd->tag, len );
        !           449:                return -EINVAL;
        !           450:        }
        !           451:        data_len = ( len - ( sizeof ( *aoehdr ) + sizeof ( *aoeata ) ) );
        !           452:        DBGC2 ( aoedev, "AoE %s/%08x ATA rsp %02x in %04zx\n",
        !           453:                aoedev_name ( aoedev ), aoecmd->tag, aoeata->cmd_stat,
        !           454:                data_len );
        !           455: 
        !           456:        /* Check for command failure */
        !           457:        if ( aoeata->cmd_stat & ATA_STAT_ERR ) {
        !           458:                DBGC ( aoedev, "AoE %s/%08x status %02x\n",
        !           459:                       aoedev_name ( aoedev ), aoecmd->tag, aoeata->cmd_stat );
        !           460:                return -EIO;
        !           461:        }
        !           462: 
        !           463:        /* Check data-in length is sufficient.  (There may be trailing
        !           464:         * garbage due to Ethernet minimum-frame-size padding.)
        !           465:         */
        !           466:        if ( data_len < command->data_in_len ) {
        !           467:                DBGC ( aoedev, "AoE %s/%08x data-in underrun (received %zd, "
        !           468:                       "expected %zd)\n", aoedev_name ( aoedev ), aoecmd->tag,
        !           469:                       data_len, command->data_in_len );
        !           470:                return -ERANGE;
        !           471:        }
        !           472: 
        !           473:        /* Copy out data payload */
        !           474:        copy_to_user ( command->data_in, 0, aoeata->data,
        !           475:                       command->data_in_len );
        !           476: 
        !           477:        return 0;
        !           478: }
        !           479: 
        !           480: /** AoE ATA command */
        !           481: static struct aoe_command_type aoecmd_ata = {
        !           482:        .cmd_len = aoecmd_ata_cmd_len,
        !           483:        .cmd = aoecmd_ata_cmd,
        !           484:        .rsp = aoecmd_ata_rsp,
        !           485: };
        !           486: 
        !           487: /**
        !           488:  * Calculate length of AoE configuration command IU
        !           489:  *
        !           490:  * @v aoecmd           AoE command
        !           491:  * @ret len            Length of command IU
        !           492:  */
        !           493: static size_t aoecmd_cfg_cmd_len ( struct aoe_command *aoecmd __unused ) {
        !           494:        return ( sizeof ( struct aoehdr ) + sizeof ( struct aoecfg ) );
        !           495: }
        !           496: 
        !           497: /**
        !           498:  * Build AoE configuration command IU
        !           499:  *
        !           500:  * @v aoecmd           AoE command
        !           501:  * @v data             Command IU
        !           502:  * @v len              Length of command IU
        !           503:  */
        !           504: static void aoecmd_cfg_cmd ( struct aoe_command *aoecmd,
        !           505:                             void *data, size_t len ) {
        !           506:        struct aoe_device *aoedev = aoecmd->aoedev;
        !           507:        struct aoehdr *aoehdr = data;
        !           508:        struct aoecfg *aoecfg = &aoehdr->payload[0].cfg;
        !           509: 
        !           510:        /* Sanity check */
        !           511:        assert ( len == ( sizeof ( *aoehdr ) + sizeof ( *aoecfg ) ) );
        !           512: 
        !           513:        /* Build IU */
        !           514:        aoehdr->command = AOE_CMD_CONFIG;
        !           515:        memset ( aoecfg, 0, sizeof ( *aoecfg ) );
        !           516: 
        !           517:        DBGC ( aoedev, "AoE %s/%08x CONFIG cmd\n",
        !           518:               aoedev_name ( aoedev ), aoecmd->tag );
        !           519: }
        !           520: 
        !           521: /**
        !           522:  * Handle AoE configuration response IU
        !           523:  *
        !           524:  * @v aoecmd           AoE command
        !           525:  * @v data             Response IU
        !           526:  * @v len              Length of response IU
        !           527:  * @v ll_source                Link-layer source address
        !           528:  * @ret rc             Return status code
        !           529:  */
        !           530: static int aoecmd_cfg_rsp ( struct aoe_command *aoecmd, const void *data,
        !           531:                            size_t len, const void *ll_source ) {
        !           532:        struct aoe_device *aoedev = aoecmd->aoedev;
        !           533:        struct ll_protocol *ll_protocol = aoedev->netdev->ll_protocol;
        !           534:        const struct aoehdr *aoehdr = data;
        !           535:        const struct aoecfg *aoecfg = &aoehdr->payload[0].cfg;
        !           536: 
        !           537:        /* Sanity check */
        !           538:        if ( len < ( sizeof ( *aoehdr ) + sizeof ( *aoecfg ) ) ) {
        !           539:                DBGC ( aoedev, "AoE %s/%08x received underlength "
        !           540:                       "configuration response (%zd bytes)\n",
        !           541:                       aoedev_name ( aoedev ), aoecmd->tag, len );
        !           542:                return -EINVAL;
        !           543:        }
        !           544:        DBGC ( aoedev, "AoE %s/%08x CONFIG rsp buf %04x fw %04x scnt %02x\n",
        !           545:               aoedev_name ( aoedev ), aoecmd->tag, ntohs ( aoecfg->bufcnt ),
        !           546:               aoecfg->fwver, aoecfg->scnt );
        !           547: 
        !           548:        /* Record target MAC address */
        !           549:        memcpy ( aoedev->target, ll_source, ll_protocol->ll_addr_len );
        !           550:        DBGC ( aoedev, "AoE %s has MAC address %s\n",
        !           551:               aoedev_name ( aoedev ), ll_protocol->ntoa ( aoedev->target ) );
        !           552: 
        !           553:        return 0;
        !           554: }
        !           555: 
        !           556: /** AoE configuration command */
        !           557: static struct aoe_command_type aoecmd_cfg = {
        !           558:        .cmd_len = aoecmd_cfg_cmd_len,
        !           559:        .cmd = aoecmd_cfg_cmd,
        !           560:        .rsp = aoecmd_cfg_rsp,
        !           561: };
        !           562: 
        !           563: /** AoE command ATA interface operations */
        !           564: static struct interface_operation aoecmd_ata_op[] = {
        !           565:        INTF_OP ( intf_close, struct aoe_command *, aoecmd_close ),
        !           566: };
        !           567: 
        !           568: /** AoE command ATA interface descriptor */
        !           569: static struct interface_descriptor aoecmd_ata_desc =
        !           570:        INTF_DESC ( struct aoe_command, ata, aoecmd_ata_op );
        !           571: 
        !           572: /**
        !           573:  * Identify AoE command by tag
        !           574:  *
        !           575:  * @v tag              Command tag
        !           576:  * @ret aoecmd         AoE command, or NULL
        !           577:  */
        !           578: static struct aoe_command * aoecmd_find_tag ( uint32_t tag ) {
        !           579:        struct aoe_command *aoecmd;
        !           580: 
        !           581:        list_for_each_entry ( aoecmd, &aoe_commands, list ) {
        !           582:                if ( aoecmd->tag == tag )
        !           583:                        return aoecmd;
        !           584:        }
        !           585:        return NULL;
        !           586: }
        !           587: 
        !           588: /**
        !           589:  * Choose an AoE command tag
        !           590:  *
        !           591:  * @ret tag            New tag, or negative error
        !           592:  */
        !           593: static int aoecmd_new_tag ( void ) {
        !           594:        static uint16_t tag_idx;
        !           595:        unsigned int i;
        !           596: 
        !           597:        for ( i = 0 ; i < 65536 ; i++ ) {
        !           598:                tag_idx++;
        !           599:                if ( aoecmd_find_tag ( tag_idx ) == NULL )
        !           600:                        return ( AOE_TAG_MAGIC | tag_idx );
        !           601:        }
        !           602:        return -EADDRINUSE;
        !           603: }
        !           604: 
        !           605: /**
        !           606:  * Create AoE command
        !           607:  *
        !           608:  * @v aoedev           AoE device
        !           609:  * @v type             AoE command type
        !           610:  * @ret aoecmd         AoE command
        !           611:  */
        !           612: static struct aoe_command * aoecmd_create ( struct aoe_device *aoedev,
        !           613:                                            struct aoe_command_type *type ) {
        !           614:        struct aoe_command *aoecmd;
        !           615:        int tag;
        !           616: 
        !           617:        /* Allocate command tag */
        !           618:        tag = aoecmd_new_tag();
        !           619:        if ( tag < 0 )
        !           620:                return NULL;
        !           621: 
        !           622:        /* Allocate and initialise structure */
        !           623:        aoecmd = zalloc ( sizeof ( *aoecmd ) );
        !           624:        if ( ! aoecmd )
        !           625:                return NULL;
        !           626:        ref_init ( &aoecmd->refcnt, aoecmd_free );
        !           627:        list_add ( &aoecmd->list, &aoe_commands );
        !           628:        intf_init ( &aoecmd->ata, &aoecmd_ata_desc, &aoecmd->refcnt );
        !           629:        timer_init ( &aoecmd->timer, aoecmd_expired, &aoecmd->refcnt );
        !           630:        aoecmd->aoedev = aoedev_get ( aoedev );
        !           631:        aoecmd->type = type;
        !           632:        aoecmd->tag = tag;
        !           633: 
        !           634:        /* Preserve timeout from last completed command */
        !           635:        aoecmd->timer.timeout = aoedev->timeout;
        !           636: 
        !           637:        /* Return already mortalised.  (Reference is held by command list.) */
        !           638:        return aoecmd;
        !           639: }
        !           640: 
        !           641: /**
        !           642:  * Issue AoE ATA command
        !           643:  *
        !           644:  * @v aoedev           AoE device
        !           645:  * @v parent           Parent interface
        !           646:  * @v command          ATA command
        !           647:  * @ret tag            Command tag, or negative error
        !           648:  */
        !           649: static int aoedev_ata_command ( struct aoe_device *aoedev,
        !           650:                                struct interface *parent,
        !           651:                                struct ata_cmd *command ) {
        !           652:        struct net_device *netdev = aoedev->netdev;
        !           653:        struct aoe_command *aoecmd;
        !           654: 
        !           655:        /* Fail immediately if net device is closed */
        !           656:        if ( ! netdev_is_open ( netdev ) ) {
        !           657:                DBGC ( aoedev, "AoE %s cannot issue command while net device "
        !           658:                       "is closed\n", aoedev_name ( aoedev ) );
        !           659:                return -EWOULDBLOCK;
        !           660:        }
        !           661: 
        !           662:        /* Create command */
        !           663:        aoecmd = aoecmd_create ( aoedev, &aoecmd_ata );
        !           664:        if ( ! aoecmd )
        !           665:                return -ENOMEM;
        !           666:        memcpy ( &aoecmd->command, command, sizeof ( aoecmd->command ) );
        !           667: 
        !           668:        /* Attempt to send command.  Allow failures to be handled by
        !           669:         * the retry timer.
        !           670:         */
        !           671:        aoecmd_tx ( aoecmd );
        !           672: 
        !           673:        /* Attach to parent interface, leave reference with command
        !           674:         * list, and return.
        !           675:         */
        !           676:        intf_plug_plug ( &aoecmd->ata, parent );
        !           677:        return aoecmd->tag;
        !           678: }
        !           679: 
        !           680: /**
        !           681:  * Issue AoE configuration command
        !           682:  *
        !           683:  * @v aoedev           AoE device
        !           684:  * @v parent           Parent interface
        !           685:  * @ret tag            Command tag, or negative error
        !           686:  */
        !           687: static int aoedev_cfg_command ( struct aoe_device *aoedev,
        !           688:                                struct interface *parent ) {
        !           689:        struct aoe_command *aoecmd;
        !           690: 
        !           691:        /* Create command */
        !           692:        aoecmd = aoecmd_create ( aoedev, &aoecmd_cfg );
        !           693:        if ( ! aoecmd )
        !           694:                return -ENOMEM;
        !           695: 
        !           696:        /* Attempt to send command.  Allow failures to be handled by
        !           697:         * the retry timer.
        !           698:         */
        !           699:        aoecmd_tx ( aoecmd );
        !           700: 
        !           701:        /* Attach to parent interface, leave reference with command
        !           702:         * list, and return.
        !           703:         */
        !           704:        intf_plug_plug ( &aoecmd->ata, parent );
        !           705:        return aoecmd->tag;
        !           706: }
        !           707: 
        !           708: /**
        !           709:  * Free AoE device
        !           710:  *
        !           711:  * @v refcnt           Reference count
        !           712:  */
        !           713: static void aoedev_free ( struct refcnt *refcnt ) {
        !           714:        struct aoe_device *aoedev =
        !           715:                container_of ( refcnt, struct aoe_device, refcnt );
        !           716: 
        !           717:        netdev_put ( aoedev->netdev );
        !           718:        free ( aoedev );
        !           719: }
        !           720: 
        !           721: /**
        !           722:  * Close AoE device
        !           723:  *
        !           724:  * @v aoedev           AoE device
        !           725:  * @v rc               Reason for close
        !           726:  */
        !           727: static void aoedev_close ( struct aoe_device *aoedev, int rc ) {
        !           728:        struct aoe_command *aoecmd;
        !           729:        struct aoe_command *tmp;
        !           730: 
        !           731:        /* Shut down interfaces */
        !           732:        intf_shutdown ( &aoedev->ata, rc );
        !           733:        intf_shutdown ( &aoedev->config, rc );
        !           734: 
        !           735:        /* Shut down any active commands */
        !           736:        list_for_each_entry_safe ( aoecmd, tmp, &aoe_commands, list ) {
        !           737:                if ( aoecmd->aoedev != aoedev )
        !           738:                        continue;
        !           739:                aoecmd_get ( aoecmd );
        !           740:                aoecmd_close ( aoecmd, rc );
        !           741:                aoecmd_put ( aoecmd );
        !           742:        }
        !           743: }
        !           744: 
        !           745: /**
        !           746:  * Check AoE device flow-control window
        !           747:  *
        !           748:  * @v aoedev           AoE device
        !           749:  * @ret len            Length of window
        !           750:  */
        !           751: static size_t aoedev_window ( struct aoe_device *aoedev ) {
        !           752:        return ( aoedev->configured ? ~( ( size_t ) 0 ) : 0 );
        !           753: }
        !           754: 
        !           755: /**
        !           756:  * Handle AoE device configuration completion
        !           757:  *
        !           758:  * @v aoedev           AoE device
        !           759:  * @v rc               Reason for completion
        !           760:  */
        !           761: static void aoedev_config_done ( struct aoe_device *aoedev, int rc ) {
        !           762: 
        !           763:        /* Shut down interface */
        !           764:        intf_shutdown ( &aoedev->config, rc );
        !           765: 
        !           766:        /* Close device on failure */
        !           767:        if ( rc != 0 ) {
        !           768:                aoedev_close ( aoedev, rc );
        !           769:                return;
        !           770:        }
        !           771: 
        !           772:        /* Mark device as configured */
        !           773:        aoedev->configured = 1;
        !           774:        xfer_window_changed ( &aoedev->ata );
        !           775: }
        !           776: 
        !           777: /**
        !           778:  * Identify device underlying AoE device
        !           779:  *
        !           780:  * @v aoedev           AoE device
        !           781:  * @ret device         Underlying device
        !           782:  */
        !           783: static struct device * aoedev_identify_device ( struct aoe_device *aoedev ) {
        !           784:        return aoedev->netdev->dev;
        !           785: }
        !           786: 
        !           787: /**
        !           788:  * Describe AoE device in an ACPI table
        !           789:  *
        !           790:  * @v aoedev           AoE device
        !           791:  * @v acpi             ACPI table
        !           792:  * @v len              Length of ACPI table
        !           793:  * @ret rc             Return status code
        !           794:  */
        !           795: static int aoedev_describe ( struct aoe_device *aoedev,
        !           796:                             struct acpi_description_header *acpi,
        !           797:                             size_t len ) {
        !           798:        struct abft_table *abft =
        !           799:                container_of ( acpi, struct abft_table, acpi );
        !           800: 
        !           801:        /* Sanity check */
        !           802:        if ( len < sizeof ( *abft ) )
        !           803:                return -ENOBUFS;
        !           804: 
        !           805:        /* Populate table */
        !           806:        abft->acpi.signature = cpu_to_le32 ( ABFT_SIG );
        !           807:        abft->acpi.length = cpu_to_le32 ( sizeof ( *abft ) );
        !           808:        abft->acpi.revision = 1;
        !           809:        abft->shelf = cpu_to_le16 ( aoedev->major );
        !           810:        abft->slot = aoedev->minor;
        !           811:        memcpy ( abft->mac, aoedev->netdev->ll_addr, sizeof ( abft->mac ) );
        !           812: 
        !           813:        return 0;
        !           814: }
        !           815: 
        !           816: /** AoE device ATA interface operations */
        !           817: static struct interface_operation aoedev_ata_op[] = {
        !           818:        INTF_OP ( ata_command, struct aoe_device *, aoedev_ata_command ),
        !           819:        INTF_OP ( xfer_window, struct aoe_device *, aoedev_window ),
        !           820:        INTF_OP ( intf_close, struct aoe_device *, aoedev_close ),
        !           821:        INTF_OP ( acpi_describe, struct aoe_device *, aoedev_describe ),
        !           822:        INTF_OP ( identify_device, struct aoe_device *,
        !           823:                  aoedev_identify_device ),
        !           824: };
        !           825: 
        !           826: /** AoE device ATA interface descriptor */
        !           827: static struct interface_descriptor aoedev_ata_desc =
        !           828:        INTF_DESC ( struct aoe_device, ata, aoedev_ata_op );
        !           829: 
        !           830: /** AoE device configuration interface operations */
        !           831: static struct interface_operation aoedev_config_op[] = {
        !           832:        INTF_OP ( intf_close, struct aoe_device *, aoedev_config_done ),
        !           833: };
        !           834: 
        !           835: /** AoE device configuration interface descriptor */
        !           836: static struct interface_descriptor aoedev_config_desc =
        !           837:        INTF_DESC ( struct aoe_device, config, aoedev_config_op );
        !           838: 
        !           839: /**
        !           840:  * Open AoE device
        !           841:  *
        !           842:  * @v parent           Parent interface
        !           843:  * @v netdev           Network device
        !           844:  * @v major            Device major number
        !           845:  * @v minor            Device minor number
        !           846:  * @ret rc             Return status code
        !           847:  */
        !           848: static int aoedev_open ( struct interface *parent, struct net_device *netdev,
        !           849:                         unsigned int major, unsigned int minor ) {
        !           850:        struct aoe_device *aoedev;
        !           851:        int rc;
        !           852: 
        !           853:        /* Allocate and initialise structure */
        !           854:        aoedev = zalloc ( sizeof ( *aoedev ) );
        !           855:        if ( ! aoedev ) {
        !           856:                rc = -ENOMEM;
        !           857:                goto err_zalloc;
        !           858:        }
        !           859:        ref_init ( &aoedev->refcnt, aoedev_free );
        !           860:        intf_init ( &aoedev->ata, &aoedev_ata_desc, &aoedev->refcnt );
        !           861:        intf_init ( &aoedev->config, &aoedev_config_desc, &aoedev->refcnt );
        !           862:        aoedev->netdev = netdev_get ( netdev );
        !           863:        aoedev->major = major;
        !           864:        aoedev->minor = minor;
        !           865:        memcpy ( aoedev->target, netdev->ll_broadcast,
        !           866:                 netdev->ll_protocol->ll_addr_len );
        !           867: 
        !           868:        /* Initiate configuration */
        !           869:        if ( ( rc = aoedev_cfg_command ( aoedev, &aoedev->config ) ) < 0 ) {
        !           870:                DBGC ( aoedev, "AoE %s could not initiate configuration: %s\n",
        !           871:                       aoedev_name ( aoedev ), strerror ( rc ) );
        !           872:                goto err_config;
        !           873:        }
        !           874: 
        !           875:        /* Attach ATA device to parent interface */
        !           876:        if ( ( rc = ata_open ( parent, &aoedev->ata, ATA_DEV_MASTER,
        !           877:                               AOE_MAX_COUNT ) ) != 0 ) {
        !           878:                DBGC ( aoedev, "AoE %s could not create ATA device: %s\n",
        !           879:                       aoedev_name ( aoedev ), strerror ( rc ) );
        !           880:                goto err_ata_open;
        !           881:        }
        !           882: 
        !           883:        /* Mortalise self and return */
        !           884:        ref_put ( &aoedev->refcnt );
        !           885:        return 0;
        !           886: 
        !           887:  err_ata_open:
        !           888:  err_config:
        !           889:        aoedev_close ( aoedev, rc );
        !           890:        ref_put ( &aoedev->refcnt );
        !           891:  err_zalloc:
        !           892:        return rc;
        !           893: }
        !           894: 
        !           895: /******************************************************************************
        !           896:  *
        !           897:  * AoE network protocol
        !           898:  *
        !           899:  ******************************************************************************
        !           900:  */
        !           901: 
        !           902: /**
        !           903:  * Process incoming AoE packets
        !           904:  *
        !           905:  * @v iobuf            I/O buffer
        !           906:  * @v netdev           Network device
        !           907:  * @v ll_dest          Link-layer destination address
        !           908:  * @v ll_source                Link-layer source address
        !           909:  * @ret rc             Return status code
        !           910:  *
        !           911:  */
        !           912: static int aoe_rx ( struct io_buffer *iobuf,
        !           913:                    struct net_device *netdev __unused,
        !           914:                    const void *ll_dest __unused,
        !           915:                    const void *ll_source ) {
        !           916:        struct aoehdr *aoehdr = iobuf->data;
        !           917:        struct aoe_command *aoecmd;
        !           918:        int rc;
        !           919: 
        !           920:        /* Sanity check */
        !           921:        if ( iob_len ( iobuf ) < sizeof ( *aoehdr ) ) {
        !           922:                DBG ( "AoE received underlength packet (%zd bytes)\n",
        !           923:                      iob_len ( iobuf ) );
        !           924:                rc = -EINVAL;
        !           925:                goto err_sanity;
        !           926:        }
        !           927:        if ( ( aoehdr->ver_flags & AOE_VERSION_MASK ) != AOE_VERSION ) {
        !           928:                DBG ( "AoE received packet for unsupported protocol version "
        !           929:                      "%02x\n", ( aoehdr->ver_flags & AOE_VERSION_MASK ) );
        !           930:                rc = -EPROTONOSUPPORT;
        !           931:                goto err_sanity;
        !           932:        }
        !           933:        if ( ! ( aoehdr->ver_flags & AOE_FL_RESPONSE ) ) {
        !           934:                DBG ( "AoE received request packet\n" );
        !           935:                rc = -EOPNOTSUPP;
        !           936:                goto err_sanity;
        !           937:        }
        !           938: 
        !           939:        /* Demultiplex amongst active AoE commands */
        !           940:        aoecmd = aoecmd_find_tag ( ntohl ( aoehdr->tag ) );
        !           941:        if ( ! aoecmd ) {
        !           942:                DBG ( "AoE received packet for unused tag %08x\n",
        !           943:                      ntohl ( aoehdr->tag ) );
        !           944:                rc = -ENOENT;
        !           945:                goto err_demux;
        !           946:        }
        !           947: 
        !           948:        /* Pass received frame to command */
        !           949:        aoecmd_get ( aoecmd );
        !           950:        if ( ( rc = aoecmd_rx ( aoecmd, iob_disown ( iobuf ),
        !           951:                                ll_source ) ) != 0 )
        !           952:                goto err_rx;
        !           953: 
        !           954:  err_rx:
        !           955:        aoecmd_put ( aoecmd );
        !           956:  err_demux:
        !           957:  err_sanity:
        !           958:        free_iob ( iobuf );
        !           959:        return rc;
        !           960: }
        !           961: 
        !           962: /** AoE protocol */
        !           963: struct net_protocol aoe_protocol __net_protocol = {
        !           964:        .name = "AoE",
        !           965:        .net_proto = htons ( ETH_P_AOE ),
        !           966:        .rx = aoe_rx,
        !           967: };
        !           968: 
        !           969: /******************************************************************************
        !           970:  *
        !           971:  * AoE URIs
        !           972:  *
        !           973:  ******************************************************************************
        !           974:  */
        !           975: 
        !           976: /**
        !           977:  * Parse AoE URI
        !           978:  *
        !           979:  * @v uri              URI
        !           980:  * @ret major          Major device number
        !           981:  * @ret minor          Minor device number
        !           982:  * @ret rc             Return status code
        !           983:  *
        !           984:  * An AoE URI has the form "aoe:e<major>.<minor>".
        !           985:  */
        !           986: static int aoe_parse_uri ( struct uri *uri, unsigned int *major,
        !           987:                           unsigned int *minor ) {
        !           988:        const char *ptr;
        !           989:        char *end;
        !           990: 
        !           991:        /* Check for URI with opaque portion */
        !           992:        if ( ! uri->opaque )
        !           993:                return -EINVAL;
        !           994:        ptr = uri->opaque;
        !           995: 
        !           996:        /* Check for initial 'e' */
        !           997:        if ( *ptr != 'e' )
        !           998:                return -EINVAL;
        !           999:        ptr++;
        !          1000: 
        !          1001:        /* Parse major device number */
        !          1002:        *major = strtoul ( ptr, &end, 10 );
        !          1003:        if ( *end != '.' )
        !          1004:                return -EINVAL;
        !          1005:        ptr = ( end + 1 );
        !          1006: 
        !          1007:        /* Parse minor device number */
        !          1008:        *minor = strtoul ( ptr, &end, 10 );
        !          1009:        if ( *end )
        !          1010:                return -EINVAL;
        !          1011: 
        !          1012:        return 0;
        !          1013: }
        !          1014: 
        !          1015: /**
        !          1016:  * Open AoE URI
        !          1017:  *
        !          1018:  * @v parent           Parent interface
        !          1019:  * @v uri              URI
        !          1020:  * @ret rc             Return status code
        !          1021:  */
        !          1022: static int aoe_open ( struct interface *parent, struct uri *uri ) {
        !          1023:        struct net_device *netdev;
        !          1024:        unsigned int major;
        !          1025:        unsigned int minor;
        !          1026:        int rc;
        !          1027: 
        !          1028:        /* Identify network device.  This is something of a hack, but
        !          1029:         * the AoE URI scheme that has been in use for some time now
        !          1030:         * provides no way to specify a particular device.
        !          1031:         */
        !          1032:        netdev = last_opened_netdev();
        !          1033:        if ( ! netdev ) {
        !          1034:                DBG ( "AoE cannot identify network device\n" );
        !          1035:                return -ENODEV;
        !          1036:        }
        !          1037: 
        !          1038:        /* Parse URI */
        !          1039:        if ( ( rc = aoe_parse_uri ( uri, &major, &minor ) ) != 0 ) {
        !          1040:                DBG ( "AoE cannot parse URI\n" );
        !          1041:                return rc;
        !          1042:        }
        !          1043: 
        !          1044:        /* Open AoE device */
        !          1045:        if ( ( rc = aoedev_open ( parent, netdev, major, minor ) ) != 0 )
        !          1046:                return rc;
        !          1047: 
        !          1048:        return 0;
        !          1049: }
        !          1050: 
        !          1051: /** AoE URI opener */
        !          1052: struct uri_opener aoe_uri_opener __uri_opener = {
        !          1053:        .scheme = "aoe",
        !          1054:        .open = aoe_open,
        !          1055: };

unix.superglobalmegacorp.com

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