iPXE
Data Structures | Functions | Variables
aoe.c File Reference

AoE protocol. More...

#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <byteswap.h>
#include <ipxe/list.h>
#include <ipxe/if_ether.h>
#include <ipxe/iobuf.h>
#include <ipxe/uaccess.h>
#include <ipxe/netdevice.h>
#include <ipxe/features.h>
#include <ipxe/interface.h>
#include <ipxe/xfer.h>
#include <ipxe/uri.h>
#include <ipxe/open.h>
#include <ipxe/ata.h>
#include <ipxe/device.h>
#include <ipxe/aoe.h>

Go to the source code of this file.

Data Structures

struct  aoe_device
 An AoE device. More...
struct  aoe_command
 An AoE command. More...
struct  aoe_command_type
 An AoE command type. More...

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
 FEATURE (FEATURE_PROTOCOL,"AoE", DHCP_EB_FEATURE_AOE, 1)
static LIST_HEAD (aoe_devices)
 List of all AoE devices.
static LIST_HEAD (aoe_commands)
 List of active AoE commands.
static struct aoe_deviceaoedev_get (struct aoe_device *aoedev)
 Get reference to AoE device.
static void aoedev_put (struct aoe_device *aoedev)
 Drop reference to AoE device.
static struct aoe_commandaoecmd_get (struct aoe_command *aoecmd)
 Get reference to AoE command.
static void aoecmd_put (struct aoe_command *aoecmd)
 Drop reference to AoE command.
static const char * aoedev_name (struct aoe_device *aoedev)
 Name AoE device.
static void aoecmd_free (struct refcnt *refcnt)
 Free AoE command.
static void aoecmd_close (struct aoe_command *aoecmd, int rc)
 Close AoE command.
static int aoecmd_tx (struct aoe_command *aoecmd)
 Transmit AoE command request.
static int aoecmd_rx (struct aoe_command *aoecmd, struct io_buffer *iobuf, const void *ll_source)
 Receive AoE command response.
static void aoecmd_expired (struct retry_timer *timer, int fail)
 Handle AoE retry timer expiry.
static size_t aoecmd_ata_cmd_len (struct aoe_command *aoecmd)
 Calculate length of AoE ATA command IU.
static void aoecmd_ata_cmd (struct aoe_command *aoecmd, void *data, size_t len)
 Build AoE ATA command IU.
static int aoecmd_ata_rsp (struct aoe_command *aoecmd, const void *data, size_t len, const void *ll_source __unused)
 Handle AoE ATA response IU.
static size_t aoecmd_cfg_cmd_len (struct aoe_command *aoecmd __unused)
 Calculate length of AoE configuration command IU.
static void aoecmd_cfg_cmd (struct aoe_command *aoecmd, void *data, size_t len)
 Build AoE configuration command IU.
static int aoecmd_cfg_rsp (struct aoe_command *aoecmd, const void *data, size_t len, const void *ll_source)
 Handle AoE configuration response IU.
static struct aoe_commandaoecmd_find_tag (uint32_t tag)
 Identify AoE command by tag.
static int aoecmd_new_tag (void)
 Choose an AoE command tag.
static struct aoe_commandaoecmd_create (struct aoe_device *aoedev, struct aoe_command_type *type)
 Create AoE command.
static int aoedev_ata_command (struct aoe_device *aoedev, struct interface *parent, struct ata_cmd *command)
 Issue AoE ATA command.
static int aoedev_cfg_command (struct aoe_device *aoedev, struct interface *parent)
 Issue AoE configuration command.
static void aoedev_free (struct refcnt *refcnt)
 Free AoE device.
static void aoedev_close (struct aoe_device *aoedev, int rc)
 Close AoE device.
static size_t aoedev_window (struct aoe_device *aoedev)
 Check AoE device flow-control window.
static void aoedev_config_done (struct aoe_device *aoedev, int rc)
 Handle AoE device configuration completion.
static struct deviceaoedev_identify_device (struct aoe_device *aoedev)
 Identify device underlying AoE device.
static struct acpi_descriptoraoedev_describe (struct aoe_device *aoedev)
 Get AoE ACPI descriptor.
static int aoedev_open (struct interface *parent, struct net_device *netdev, unsigned int major, unsigned int minor)
 Open AoE device.
static int aoe_rx (struct io_buffer *iobuf, struct net_device *netdev __unused, const void *ll_dest __unused, const void *ll_source, unsigned int flags __unused)
 Process incoming AoE packets.
static int aoe_parse_uri (struct uri *uri, unsigned int *major, unsigned int *minor)
 Parse AoE URI.
static int aoe_open (struct interface *parent, struct uri *uri)
 Open AoE URI.
static int abft_complete (struct acpi_descriptor *desc __unused)
 Check if AoE boot firmware table descriptor is complete.
static int abft_install (int(*install)(struct acpi_header *acpi))
 Install AoE boot firmware table(s)

Variables

struct net_protocol aoe_protocol __net_protocol
 AoE protocol.
struct acpi_model abft_model __acpi_model
 aBFT model
static struct aoe_command_type aoecmd_ata
 AoE ATA command.
static struct aoe_command_type aoecmd_cfg
 AoE configuration command.
static struct interface_operation aoecmd_ata_op []
 AoE command ATA interface operations.
static struct interface_descriptor aoecmd_ata_desc
 AoE command ATA interface descriptor.
static struct interface_operation aoedev_ata_op []
 AoE device ATA interface operations.
static struct interface_descriptor aoedev_ata_desc
 AoE device ATA interface descriptor.
static struct interface_operation aoedev_config_op []
 AoE device configuration interface operations.
static struct interface_descriptor aoedev_config_desc
 AoE device configuration interface descriptor.
struct uri_opener aoe_uri_opener __uri_opener
 AoE URI opener.

Detailed Description

AoE protocol.

Definition in file aoe.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
FEATURE ( FEATURE_PROTOCOL  ,
"AoE"  ,
DHCP_EB_FEATURE_AOE  ,
 
)
static LIST_HEAD ( aoe_devices  ) [static]

List of all AoE devices.

static LIST_HEAD ( aoe_commands  ) [static]

List of active AoE commands.

static struct aoe_device* aoedev_get ( struct aoe_device aoedev) [static, read]

Get reference to AoE device.

Parameters:
aoedevAoE device
Return values:
aoedevAoE device

Definition at line 160 of file aoe.c.

References aoe_command::aoedev, and ref_get.

Referenced by aoecmd_create().

                                         {
        ref_get ( &aoedev->refcnt );
        return aoedev;
}
static void aoedev_put ( struct aoe_device aoedev) [inline, static]

Drop reference to AoE device.

Parameters:
aoedevAoE device

Definition at line 171 of file aoe.c.

References ref_put.

Referenced by aoecmd_free().

                                         {
        ref_put ( &aoedev->refcnt );
}
static struct aoe_command* aoecmd_get ( struct aoe_command aoecmd) [static, read]

Get reference to AoE command.

Parameters:
aoecmdAoE command
Return values:
aoecmdAoE command

Definition at line 182 of file aoe.c.

References ref_get.

Referenced by aoe_rx(), and aoedev_close().

                                          {
        ref_get ( &aoecmd->refcnt );
        return aoecmd;
}
static void aoecmd_put ( struct aoe_command aoecmd) [inline, static]

Drop reference to AoE command.

Parameters:
aoecmdAoE command

Definition at line 193 of file aoe.c.

References ref_put.

Referenced by aoe_rx(), aoecmd_close(), and aoedev_close().

                                          {
        ref_put ( &aoecmd->refcnt );
}
static const char* aoedev_name ( struct aoe_device aoedev) [static]

Name AoE device.

Parameters:
aoedevAoE device
Return values:
nameAoE device name

Definition at line 203 of file aoe.c.

References aoe_device::major, aoe_device::minor, net_device::name, aoe_device::netdev, and snprintf().

Referenced by abft_install(), aoecmd_ata_cmd(), aoecmd_ata_rsp(), aoecmd_cfg_cmd(), aoecmd_cfg_rsp(), aoecmd_rx(), aoecmd_tx(), aoedev_ata_command(), and aoedev_open().

                                                              {
        static char buf[16];

        snprintf ( buf, sizeof ( buf ), "%s/e%d.%d", aoedev->netdev->name,
                   aoedev->major, aoedev->minor );
        return buf;
}
static void aoecmd_free ( struct refcnt refcnt) [static]

Free AoE command.

Parameters:
refcntReference counter

Definition at line 216 of file aoe.c.

References aoe_command::aoedev, aoedev_put(), assert, container_of, free, aoe_command::list, list_empty, and aoe_command::timer.

Referenced by aoecmd_create().

                                                  {
        struct aoe_command *aoecmd =
                container_of ( refcnt, struct aoe_command, refcnt );

        assert ( ! timer_running ( &aoecmd->timer ) );
        assert ( list_empty ( &aoecmd->list ) );

        aoedev_put ( aoecmd->aoedev );
        free ( aoecmd );
}
static void aoecmd_close ( struct aoe_command aoecmd,
int  rc 
) [static]

Close AoE command.

Parameters:
aoecmdAoE command
rcReason for close

Definition at line 233 of file aoe.c.

References aoecmd_put(), aoe_command::aoedev, aoe_command::ata, INIT_LIST_HEAD, intf_shutdown(), aoe_command::list, list_del, list_empty, stop_timer(), retry_timer::timeout, aoe_device::timeout, and aoe_command::timer.

Referenced by aoecmd_expired(), aoecmd_rx(), and aoedev_close().

                                                                {
        struct aoe_device *aoedev = aoecmd->aoedev;

        /* Stop timer */
        stop_timer ( &aoecmd->timer );

        /* Preserve the timeout value for subsequent commands */
        aoedev->timeout = aoecmd->timer.timeout;

        /* Remove from list of commands */
        if ( ! list_empty ( &aoecmd->list ) ) {
                list_del ( &aoecmd->list );
                INIT_LIST_HEAD ( &aoecmd->list );
                aoecmd_put ( aoecmd );
        }

        /* Shut down interfaces */
        intf_shutdown ( &aoecmd->ata, rc );
}
static int aoecmd_tx ( struct aoe_command aoecmd) [static]

Transmit AoE command request.

Parameters:
aoecmdAoE command
Return values:
rcReturn status code

Definition at line 259 of file aoe.c.

References alloc_iob(), AOE_VERSION, aoe_command::aoedev, aoedev_name(), assert, aoe_command_type::cmd, aoe_command_type::cmd_len, io_buffer::data, DBGC, ENOMEM, htonl, htons, iob_len(), iob_put, iob_reserve, net_device::ll_addr, aoehdr::major, aoe_device::major, MAX_LL_HEADER_LEN, memset(), aoehdr::minor, aoe_device::minor, net_tx(), netdev, aoe_device::netdev, NULL, rc, start_timer(), strerror(), aoehdr::tag, aoe_command::tag, aoe_device::target, aoe_command::timer, aoe_command::type, and aoehdr::ver_flags.

Referenced by aoecmd_expired(), aoedev_ata_command(), and aoedev_cfg_command().

                                                    {
        struct aoe_device *aoedev = aoecmd->aoedev;
        struct net_device *netdev = aoedev->netdev;
        struct io_buffer *iobuf;
        struct aoehdr *aoehdr;
        size_t cmd_len;
        int rc;

        /* Sanity check */
        assert ( netdev != NULL );

        /* If we are transmitting anything that requires a response,
         * start the retransmission timer.  Do this before attempting
         * to allocate the I/O buffer, in case allocation itself
         * fails.
         */
        start_timer ( &aoecmd->timer );

        /* Create outgoing I/O buffer */
        cmd_len = aoecmd->type->cmd_len ( aoecmd );
        iobuf = alloc_iob ( MAX_LL_HEADER_LEN + cmd_len );
        if ( ! iobuf )
                return -ENOMEM;
        iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
        aoehdr = iob_put ( iobuf, cmd_len );

        /* Fill AoE header */
        memset ( aoehdr, 0, sizeof ( *aoehdr ) );
        aoehdr->ver_flags = AOE_VERSION;
        aoehdr->major = htons ( aoedev->major );
        aoehdr->minor = aoedev->minor;
        aoehdr->tag = htonl ( aoecmd->tag );
        aoecmd->type->cmd ( aoecmd, iobuf->data, iob_len ( iobuf ) );

        /* Send packet */
        if ( ( rc = net_tx ( iobuf, netdev, &aoe_protocol, aoedev->target,
                             netdev->ll_addr ) ) != 0 ) {
                DBGC ( aoedev, "AoE %s/%08x could not transmit: %s\n",
                       aoedev_name ( aoedev ), aoecmd->tag,
                       strerror ( rc ) );
                return rc;
        }

        return 0;
}
static int aoecmd_rx ( struct aoe_command aoecmd,
struct io_buffer iobuf,
const void *  ll_source 
) [static]

Receive AoE command response.

Parameters:
aoecmdAoE command
iobufI/O buffer
ll_sourceLink-layer source address
Return values:
rcReturn status code

Definition at line 313 of file aoe.c.

References AOE_FL_ERROR, aoecmd_close(), aoe_command::aoedev, aoedev_name(), io_buffer::data, DBGC, done, EINVAL, EIO, free_iob(), iob_len(), aoehdr::major, aoe_device::major, aoehdr::minor, aoe_device::minor, ntohs, rc, aoe_command_type::rsp, aoe_command::tag, aoe_command::type, and aoehdr::ver_flags.

Referenced by aoe_rx().

                                               {
        struct aoe_device *aoedev = aoecmd->aoedev;
        struct aoehdr *aoehdr = iobuf->data;
        int rc;

        /* Sanity check */
        if ( iob_len ( iobuf ) < sizeof ( *aoehdr ) ) {
                DBGC ( aoedev, "AoE %s/%08x received underlength response "
                       "(%zd bytes)\n", aoedev_name ( aoedev ),
                       aoecmd->tag, iob_len ( iobuf ) );
                rc = -EINVAL;
                goto done;
        }
        if ( ( ntohs ( aoehdr->major ) != aoedev->major ) ||
             ( aoehdr->minor != aoedev->minor ) ) {
                DBGC ( aoedev, "AoE %s/%08x received response for incorrect "
                       "device e%d.%d\n", aoedev_name ( aoedev ), aoecmd->tag,
                       ntohs ( aoehdr->major ), aoehdr->minor );
                rc = -EINVAL;
                goto done;
        }

        /* Catch command failures */
        if ( aoehdr->ver_flags & AOE_FL_ERROR ) {
                DBGC ( aoedev, "AoE %s/%08x terminated in error\n",
                       aoedev_name ( aoedev ), aoecmd->tag );
                aoecmd_close ( aoecmd, -EIO );
                rc = -EIO;
                goto done;
        }

        /* Hand off to command completion handler */
        if ( ( rc = aoecmd->type->rsp ( aoecmd, iobuf->data, iob_len ( iobuf ),
                                        ll_source ) ) != 0 )
                goto done;

 done:
        /* Free I/O buffer */
        free_iob ( iobuf );

        /* Terminate command */
        aoecmd_close ( aoecmd, rc );

        return rc;
}
static void aoecmd_expired ( struct retry_timer timer,
int  fail 
) [static]

Handle AoE retry timer expiry.

Parameters:
timerAoE retry timer
failFailure indicator

Definition at line 366 of file aoe.c.

References aoecmd_close(), aoecmd_tx(), container_of, and ETIMEDOUT.

Referenced by aoecmd_create().

                                                                   {
        struct aoe_command *aoecmd =
                container_of ( timer, struct aoe_command, timer );

        if ( fail ) {
                aoecmd_close ( aoecmd, -ETIMEDOUT );
        } else {
                aoecmd_tx ( aoecmd );
        }
}
static size_t aoecmd_ata_cmd_len ( struct aoe_command aoecmd) [static]

Calculate length of AoE ATA command IU.

Parameters:
aoecmdAoE command
Return values:
lenLength of command IU

Definition at line 383 of file aoe.c.

References aoe_command::command, and ata_cmd::data_out_len.

                                                                {
        struct ata_cmd *command = &aoecmd->command;

        return ( sizeof ( struct aoehdr ) + sizeof ( struct aoeata ) +
                 command->data_out_len );
}
static void aoecmd_ata_cmd ( struct aoe_command aoecmd,
void *  data,
size_t  len 
) [static]

Build AoE ATA command IU.

Parameters:
aoecmdAoE command
dataCommand IU
lenLength of command IU

Definition at line 397 of file aoe.c.

References aoeata::aflags, AOE_CMD_ATA, AOE_FL_DEV_HEAD, AOE_FL_EXTENDED, AOE_FL_WRITE, aoe_command::aoedev, aoedev_name(), assert, aoecmd::ata, ATA_DEV_MASK, ATA_DEV_SLAVE, aoeata::bytes, ata_fifo::bytes, ata_cmd::cb, aoeata::cmd_stat, ata_cb::cmd_stat, aoehdr::command, aoe_command::command, copy_from_user(), aoeata::count, ata_cb::count, cpu_to_le64, ata_fifo::cur, aoeata::data, data, ata_cmd::data_in_len, ata_cmd::data_out, ata_cmd::data_out_len, DBGC2, ata_cb::device, aoeata::err_feat, ata_cb::err_feat, aoeata::lba, ata_cb::lba, ata_cb::lba48, linker_assert, memset(), ata_lba::native, ata_fifo::native, aoehdr::payload, aoe_command::tag, and aoeata::u64.

                                                      {
        struct aoe_device *aoedev = aoecmd->aoedev;
        struct ata_cmd *command = &aoecmd->command;
        struct aoehdr *aoehdr = data;
        struct aoeata *aoeata = &aoehdr->payload[0].ata;

        /* Sanity check */
        linker_assert ( AOE_FL_DEV_HEAD == ATA_DEV_SLAVE, __fix_ata_h__ );
        assert ( len == ( sizeof ( *aoehdr ) + sizeof ( *aoeata ) +
                          command->data_out_len ) );

        /* Build IU */
        aoehdr->command = AOE_CMD_ATA;
        memset ( aoeata, 0, sizeof ( *aoeata ) );
        aoeata->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 ) |
                           ( command->cb.device & ATA_DEV_SLAVE ) |
                           ( command->data_out_len ? AOE_FL_WRITE : 0 ) );
        aoeata->err_feat = command->cb.err_feat.bytes.cur;
        aoeata->count = command->cb.count.native;
        aoeata->cmd_stat = command->cb.cmd_stat;
        aoeata->lba.u64 = cpu_to_le64 ( command->cb.lba.native );
        if ( ! command->cb.lba48 )
                aoeata->lba.bytes[3] |=
                        ( command->cb.device & ATA_DEV_MASK );
        copy_from_user ( aoeata->data, command->data_out, 0,
                         command->data_out_len );

        DBGC2 ( aoedev, "AoE %s/%08x ATA cmd %02x:%02x:%02x:%02x:%08llx",
                aoedev_name ( aoedev ), aoecmd->tag, aoeata->aflags,
                aoeata->err_feat, aoeata->count, aoeata->cmd_stat,
                aoeata->lba.u64 );
        if ( command->data_out_len )
                DBGC2 ( aoedev, " out %04zx", command->data_out_len );
        if ( command->data_in_len )
                DBGC2 ( aoedev, " in %04zx", command->data_in_len );
        DBGC2 ( aoedev, "\n" );
}
static int aoecmd_ata_rsp ( struct aoe_command aoecmd,
const void *  data,
size_t  len,
const void *ll_source  __unused 
) [static]

Handle AoE ATA response IU.

Parameters:
aoecmdAoE command
dataResponse IU
lenLength of response IU
ll_sourceLink-layer source address
Return values:
rcReturn status code

Definition at line 445 of file aoe.c.

References aoe_command::aoedev, aoedev_name(), aoecmd::ata, ATA_STAT_ERR, aoeata::cmd_stat, aoe_command::command, copy_to_user(), aoeata::data, data, ata_cmd::data_in, ata_cmd::data_in_len, DBGC, DBGC2, EINVAL, EIO, ERANGE, aoehdr::payload, and aoe_command::tag.

                                                                         {
        struct aoe_device *aoedev = aoecmd->aoedev;
        struct ata_cmd *command = &aoecmd->command;
        const struct aoehdr *aoehdr = data;
        const struct aoeata *aoeata = &aoehdr->payload[0].ata;
        size_t data_len;

        /* Sanity check */
        if ( len < ( sizeof ( *aoehdr ) + sizeof ( *aoeata ) ) ) {
                DBGC ( aoedev, "AoE %s/%08x received underlength ATA response "
                       "(%zd bytes)\n", aoedev_name ( aoedev ),
                       aoecmd->tag, len );
                return -EINVAL;
        }
        data_len = ( len - ( sizeof ( *aoehdr ) + sizeof ( *aoeata ) ) );
        DBGC2 ( aoedev, "AoE %s/%08x ATA rsp %02x in %04zx\n",
                aoedev_name ( aoedev ), aoecmd->tag, aoeata->cmd_stat,
                data_len );

        /* Check for command failure */
        if ( aoeata->cmd_stat & ATA_STAT_ERR ) {
                DBGC ( aoedev, "AoE %s/%08x status %02x\n",
                       aoedev_name ( aoedev ), aoecmd->tag, aoeata->cmd_stat );
                return -EIO;
        }

        /* Check data-in length is sufficient.  (There may be trailing
         * garbage due to Ethernet minimum-frame-size padding.)
         */
        if ( data_len < command->data_in_len ) {
                DBGC ( aoedev, "AoE %s/%08x data-in underrun (received %zd, "
                       "expected %zd)\n", aoedev_name ( aoedev ), aoecmd->tag,
                       data_len, command->data_in_len );
                return -ERANGE;
        }

        /* Copy out data payload */
        copy_to_user ( command->data_in, 0, aoeata->data,
                       command->data_in_len );

        return 0;
}
static size_t aoecmd_cfg_cmd_len ( struct aoe_command *aoecmd  __unused) [static]

Calculate length of AoE configuration command IU.

Parameters:
aoecmdAoE command
Return values:
lenLength of command IU

Definition at line 502 of file aoe.c.

                                                                         {
        return ( sizeof ( struct aoehdr ) + sizeof ( struct aoecfg ) );
}
static void aoecmd_cfg_cmd ( struct aoe_command aoecmd,
void *  data,
size_t  len 
) [static]

Build AoE configuration command IU.

Parameters:
aoecmdAoE command
dataCommand IU
lenLength of command IU

Definition at line 513 of file aoe.c.

References AOE_CMD_CONFIG, aoe_command::aoedev, aoedev_name(), assert, aoecmd::cfg, aoehdr::command, data, DBGC, memset(), aoehdr::payload, and aoe_command::tag.

                                                      {
        struct aoe_device *aoedev = aoecmd->aoedev;
        struct aoehdr *aoehdr = data;
        struct aoecfg *aoecfg = &aoehdr->payload[0].cfg;

        /* Sanity check */
        assert ( len == ( sizeof ( *aoehdr ) + sizeof ( *aoecfg ) ) );

        /* Build IU */
        aoehdr->command = AOE_CMD_CONFIG;
        memset ( aoecfg, 0, sizeof ( *aoecfg ) );

        DBGC ( aoedev, "AoE %s/%08x CONFIG cmd\n",
               aoedev_name ( aoedev ), aoecmd->tag );
}
static int aoecmd_cfg_rsp ( struct aoe_command aoecmd,
const void *  data,
size_t  len,
const void *  ll_source 
) [static]

Handle AoE configuration response IU.

Parameters:
aoecmdAoE command
dataResponse IU
lenLength of response IU
ll_sourceLink-layer source address
Return values:
rcReturn status code

Definition at line 539 of file aoe.c.

References aoe_command::aoedev, aoedev_name(), aoecfg::bufcnt, aoecmd::cfg, data, DBGC, EINVAL, aoecfg::fwver, ll_protocol::ll_addr_len, net_device::ll_protocol, memcpy(), aoe_device::netdev, ll_protocol::ntoa, ntohs, aoehdr::payload, aoecfg::scnt, aoe_command::tag, and aoe_device::target.

                                                                {
        struct aoe_device *aoedev = aoecmd->aoedev;
        struct ll_protocol *ll_protocol = aoedev->netdev->ll_protocol;
        const struct aoehdr *aoehdr = data;
        const struct aoecfg *aoecfg = &aoehdr->payload[0].cfg;

        /* Sanity check */
        if ( len < ( sizeof ( *aoehdr ) + sizeof ( *aoecfg ) ) ) {
                DBGC ( aoedev, "AoE %s/%08x received underlength "
                       "configuration response (%zd bytes)\n",
                       aoedev_name ( aoedev ), aoecmd->tag, len );
                return -EINVAL;
        }
        DBGC ( aoedev, "AoE %s/%08x CONFIG rsp buf %04x fw %04x scnt %02x\n",
               aoedev_name ( aoedev ), aoecmd->tag, ntohs ( aoecfg->bufcnt ),
               aoecfg->fwver, aoecfg->scnt );

        /* Record target MAC address */
        memcpy ( aoedev->target, ll_source, ll_protocol->ll_addr_len );
        DBGC ( aoedev, "AoE %s has MAC address %s\n",
               aoedev_name ( aoedev ), ll_protocol->ntoa ( aoedev->target ) );

        return 0;
}
static struct aoe_command* aoecmd_find_tag ( uint32_t  tag) [static, read]

Identify AoE command by tag.

Parameters:
tagCommand tag
Return values:
aoecmdAoE command, or NULL

Definition at line 587 of file aoe.c.

References aoe_command::list, list_for_each_entry, NULL, and aoe_command::tag.

Referenced by aoe_rx(), and aoecmd_new_tag().

                                                             {
        struct aoe_command *aoecmd;

        list_for_each_entry ( aoecmd, &aoe_commands, list ) {
                if ( aoecmd->tag == tag )
                        return aoecmd;
        }
        return NULL;
}
static int aoecmd_new_tag ( void  ) [static]

Choose an AoE command tag.

Return values:
tagNew tag, or negative error

Definition at line 602 of file aoe.c.

References AOE_TAG_MAGIC, aoecmd_find_tag(), EADDRINUSE, and NULL.

Referenced by aoecmd_create().

                                   {
        static uint16_t tag_idx;
        unsigned int i;

        for ( i = 0 ; i < 65536 ; i++ ) {
                tag_idx++;
                if ( aoecmd_find_tag ( tag_idx ) == NULL )
                        return ( AOE_TAG_MAGIC | tag_idx );
        }
        return -EADDRINUSE;
}
static struct aoe_command* aoecmd_create ( struct aoe_device aoedev,
struct aoe_command_type type 
) [static, read]

Create AoE command.

Parameters:
aoedevAoE device
typeAoE command type
Return values:
aoecmdAoE command

Definition at line 621 of file aoe.c.

References aoecmd_expired(), aoecmd_free(), aoecmd_new_tag(), aoe_command::aoedev, aoedev_get(), aoe_command::ata, intf_init(), aoe_command::list, list_add, NULL, ref_init, aoe_command::refcnt, aoe_command::tag, tag, retry_timer::timeout, aoe_device::timeout, aoe_command::timer, aoe_command::type, type, and zalloc().

Referenced by aoedev_ata_command(), and aoedev_cfg_command().

                                                                            {
        struct aoe_command *aoecmd;
        int tag;

        /* Allocate command tag */
        tag = aoecmd_new_tag();
        if ( tag < 0 )
                return NULL;

        /* Allocate and initialise structure */
        aoecmd = zalloc ( sizeof ( *aoecmd ) );
        if ( ! aoecmd )
                return NULL;
        ref_init ( &aoecmd->refcnt, aoecmd_free );
        list_add ( &aoecmd->list, &aoe_commands );
        intf_init ( &aoecmd->ata, &aoecmd_ata_desc, &aoecmd->refcnt );
        timer_init ( &aoecmd->timer, aoecmd_expired, &aoecmd->refcnt );
        aoecmd->aoedev = aoedev_get ( aoedev );
        aoecmd->type = type;
        aoecmd->tag = tag;

        /* Preserve timeout from last completed command */
        aoecmd->timer.timeout = aoedev->timeout;

        /* Return already mortalised.  (Reference is held by command list.) */
        return aoecmd;
}
static int aoedev_ata_command ( struct aoe_device aoedev,
struct interface parent,
struct ata_cmd command 
) [static]

Issue AoE ATA command.

Parameters:
aoedevAoE device
parentParent interface
commandATA command
Return values:
tagCommand tag, or negative error

Definition at line 658 of file aoe.c.

References aoecmd_create(), aoecmd_tx(), aoedev_name(), aoe_command::ata, aoe_command::command, DBGC, ENOMEM, EWOULDBLOCK, intf_plug_plug(), memcpy(), netdev, aoe_device::netdev, netdev_is_open(), and aoe_command::tag.

                                                          {
        struct net_device *netdev = aoedev->netdev;
        struct aoe_command *aoecmd;

        /* Fail immediately if net device is closed */
        if ( ! netdev_is_open ( netdev ) ) {
                DBGC ( aoedev, "AoE %s cannot issue command while net device "
                       "is closed\n", aoedev_name ( aoedev ) );
                return -EWOULDBLOCK;
        }

        /* Create command */
        aoecmd = aoecmd_create ( aoedev, &aoecmd_ata );
        if ( ! aoecmd )
                return -ENOMEM;
        memcpy ( &aoecmd->command, command, sizeof ( aoecmd->command ) );

        /* Attempt to send command.  Allow failures to be handled by
         * the retry timer.
         */
        aoecmd_tx ( aoecmd );

        /* Attach to parent interface, leave reference with command
         * list, and return.
         */
        intf_plug_plug ( &aoecmd->ata, parent );
        return aoecmd->tag;
}
static int aoedev_cfg_command ( struct aoe_device aoedev,
struct interface parent 
) [static]

Issue AoE configuration command.

Parameters:
aoedevAoE device
parentParent interface
Return values:
tagCommand tag, or negative error

Definition at line 696 of file aoe.c.

References aoecmd_create(), aoecmd_tx(), aoe_command::ata, ENOMEM, intf_plug_plug(), and aoe_command::tag.

Referenced by aoedev_open().

                                                           {
        struct aoe_command *aoecmd;

        /* Create command */
        aoecmd = aoecmd_create ( aoedev, &aoecmd_cfg );
        if ( ! aoecmd )
                return -ENOMEM;

        /* Attempt to send command.  Allow failures to be handled by
         * the retry timer.
         */
        aoecmd_tx ( aoecmd );

        /* Attach to parent interface, leave reference with command
         * list, and return.
         */
        intf_plug_plug ( &aoecmd->ata, parent );
        return aoecmd->tag;
}
static void aoedev_free ( struct refcnt refcnt) [static]

Free AoE device.

Parameters:
refcntReference count

Definition at line 722 of file aoe.c.

References container_of, free, aoe_device::netdev, and netdev_put().

Referenced by aoedev_open().

                                                  {
        struct aoe_device *aoedev =
                container_of ( refcnt, struct aoe_device, refcnt );

        netdev_put ( aoedev->netdev );
        free ( aoedev );
}
static void aoedev_close ( struct aoe_device aoedev,
int  rc 
) [static]

Close AoE device.

Parameters:
aoedevAoE device
rcReason for close

Definition at line 736 of file aoe.c.

References aoecmd_close(), aoecmd_get(), aoecmd_put(), aoe_command::aoedev, aoe_device::ata, aoe_device::config, intf_shutdown(), aoe_command::list, and list_for_each_entry_safe.

Referenced by aoedev_config_done(), and aoedev_open().

                                                               {
        struct aoe_command *aoecmd;
        struct aoe_command *tmp;

        /* Shut down interfaces */
        intf_shutdown ( &aoedev->ata, rc );
        intf_shutdown ( &aoedev->config, rc );

        /* Shut down any active commands */
        list_for_each_entry_safe ( aoecmd, tmp, &aoe_commands, list ) {
                if ( aoecmd->aoedev != aoedev )
                        continue;
                aoecmd_get ( aoecmd );
                aoecmd_close ( aoecmd, rc );
                aoecmd_put ( aoecmd );
        }
}
static size_t aoedev_window ( struct aoe_device aoedev) [static]

Check AoE device flow-control window.

Parameters:
aoedevAoE device
Return values:
lenLength of window

Definition at line 760 of file aoe.c.

References aoe_device::configured.

                                                          {
        return ( aoedev->configured ? ~( ( size_t ) 0 ) : 0 );
}
static void aoedev_config_done ( struct aoe_device aoedev,
int  rc 
) [static]

Handle AoE device configuration completion.

Parameters:
aoedevAoE device
rcReason for completion

Definition at line 770 of file aoe.c.

References aoedev_close(), aoe_device::ata, aoe_device::config, aoe_device::configured, intf_shutdown(), and xfer_window_changed().

                                                                     {

        /* Shut down interface */
        intf_shutdown ( &aoedev->config, rc );

        /* Close device on failure */
        if ( rc != 0 ) {
                aoedev_close ( aoedev, rc );
                return;
        }

        /* Mark device as configured */
        aoedev->configured = 1;
        xfer_window_changed ( &aoedev->ata );
}
static struct device* aoedev_identify_device ( struct aoe_device aoedev) [static, read]

Identify device underlying AoE device.

Parameters:
aoedevAoE device
Return values:
deviceUnderlying device

Definition at line 792 of file aoe.c.

References net_device::dev, and aoe_device::netdev.

                                                                            {
        return aoedev->netdev->dev;
}
static struct acpi_descriptor* aoedev_describe ( struct aoe_device aoedev) [static, read]

Get AoE ACPI descriptor.

Parameters:
aoedevAoE device
Return values:
descACPI descriptor

Definition at line 802 of file aoe.c.

References aoe_device::desc.

                                                                              {
        return &aoedev->desc;
}
static int aoedev_open ( struct interface parent,
struct net_device netdev,
unsigned int  major,
unsigned int  minor 
) [static]

Open AoE device.

Parameters:
parentParent interface
netdevNetwork device
majorDevice major number
minorDevice minor number
Return values:
rcReturn status code

Definition at line 838 of file aoe.c.

References acpi_init(), AOE_MAX_COUNT, aoedev_cfg_command(), aoedev_close(), aoedev_free(), aoedev_name(), aoe_device::ata, ATA_DEV_MASTER, ata_open(), aoe_device::config, DBGC, aoe_device::desc, ENOMEM, intf_init(), ll_protocol::ll_addr_len, net_device::ll_broadcast, net_device::ll_protocol, major, aoe_device::major, memcpy(), minor, aoe_device::minor, aoe_device::netdev, netdev_get(), rc, ref_init, ref_put, aoe_device::refcnt, strerror(), aoe_device::target, and zalloc().

Referenced by aoe_open().

                                                                  {
        struct aoe_device *aoedev;
        int rc;

        /* Allocate and initialise structure */
        aoedev = zalloc ( sizeof ( *aoedev ) );
        if ( ! aoedev ) {
                rc = -ENOMEM;
                goto err_zalloc;
        }
        ref_init ( &aoedev->refcnt, aoedev_free );
        intf_init ( &aoedev->ata, &aoedev_ata_desc, &aoedev->refcnt );
        intf_init ( &aoedev->config, &aoedev_config_desc, &aoedev->refcnt );
        aoedev->netdev = netdev_get ( netdev );
        aoedev->major = major;
        aoedev->minor = minor;
        memcpy ( aoedev->target, netdev->ll_broadcast,
                 netdev->ll_protocol->ll_addr_len );
        acpi_init ( &aoedev->desc, &abft_model, &aoedev->refcnt );

        /* Initiate configuration */
        if ( ( rc = aoedev_cfg_command ( aoedev, &aoedev->config ) ) < 0 ) {
                DBGC ( aoedev, "AoE %s could not initiate configuration: %s\n",
                       aoedev_name ( aoedev ), strerror ( rc ) );
                goto err_config;
        }

        /* Attach ATA device to parent interface */
        if ( ( rc = ata_open ( parent, &aoedev->ata, ATA_DEV_MASTER,
                               AOE_MAX_COUNT ) ) != 0 ) {
                DBGC ( aoedev, "AoE %s could not create ATA device: %s\n",
                       aoedev_name ( aoedev ), strerror ( rc ) );
                goto err_ata_open;
        }

        /* Mortalise self and return */
        ref_put ( &aoedev->refcnt );
        return 0;

 err_ata_open:
 err_config:
        aoedev_close ( aoedev, rc );
        ref_put ( &aoedev->refcnt );
 err_zalloc:
        return rc;
}
static int aoe_rx ( struct io_buffer iobuf,
struct net_device *netdev  __unused,
const void *ll_dest  __unused,
const void *  ll_source,
unsigned int flags  __unused 
) [static]

Process incoming AoE packets.

Parameters:
iobufI/O buffer
netdevNetwork device
ll_destLink-layer destination address
ll_sourceLink-layer source address
flagsPacket flags
Return values:
rcReturn status code

Definition at line 903 of file aoe.c.

References AOE_FL_RESPONSE, AOE_VERSION, AOE_VERSION_MASK, aoecmd_find_tag(), aoecmd_get(), aoecmd_put(), aoecmd_rx(), io_buffer::data, DBG, EINVAL, ENOENT, EOPNOTSUPP, EPROTONOSUPPORT, free_iob(), iob_disown, iob_len(), ntohl, rc, aoehdr::tag, and aoehdr::ver_flags.

                                                  {
        struct aoehdr *aoehdr = iobuf->data;
        struct aoe_command *aoecmd;
        int rc;

        /* Sanity check */
        if ( iob_len ( iobuf ) < sizeof ( *aoehdr ) ) {
                DBG ( "AoE received underlength packet (%zd bytes)\n",
                      iob_len ( iobuf ) );
                rc = -EINVAL;
                goto err_sanity;
        }
        if ( ( aoehdr->ver_flags & AOE_VERSION_MASK ) != AOE_VERSION ) {
                DBG ( "AoE received packet for unsupported protocol version "
                      "%02x\n", ( aoehdr->ver_flags & AOE_VERSION_MASK ) );
                rc = -EPROTONOSUPPORT;
                goto err_sanity;
        }
        if ( ! ( aoehdr->ver_flags & AOE_FL_RESPONSE ) ) {
                DBG ( "AoE received request packet\n" );
                rc = -EOPNOTSUPP;
                goto err_sanity;
        }

        /* Demultiplex amongst active AoE commands */
        aoecmd = aoecmd_find_tag ( ntohl ( aoehdr->tag ) );
        if ( ! aoecmd ) {
                DBG ( "AoE received packet for unused tag %08x\n",
                      ntohl ( aoehdr->tag ) );
                rc = -ENOENT;
                goto err_demux;
        }

        /* Pass received frame to command */
        aoecmd_get ( aoecmd );
        if ( ( rc = aoecmd_rx ( aoecmd, iob_disown ( iobuf ),
                                ll_source ) ) != 0 )
                goto err_rx;

 err_rx:
        aoecmd_put ( aoecmd );
 err_demux:
 err_sanity:
        free_iob ( iobuf );
        return rc;
}
static int aoe_parse_uri ( struct uri uri,
unsigned int *  major,
unsigned int *  minor 
) [static]

Parse AoE URI.

Parameters:
uriURI
Return values:
majorMajor device number
minorMinor device number
rcReturn status code

An AoE URI has the form "aoe:e<major>.<minor>".

Definition at line 978 of file aoe.c.

References EINVAL, end, uri::opaque, and strtoul().

Referenced by aoe_open().

                                                 {
        const char *ptr;
        char *end;

        /* Check for URI with opaque portion */
        if ( ! uri->opaque )
                return -EINVAL;
        ptr = uri->opaque;

        /* Check for initial 'e' */
        if ( *ptr != 'e' )
                return -EINVAL;
        ptr++;

        /* Parse major device number */
        *major = strtoul ( ptr, &end, 10 );
        if ( *end != '.' )
                return -EINVAL;
        ptr = ( end + 1 );

        /* Parse minor device number */
        *minor = strtoul ( ptr, &end, 10 );
        if ( *end )
                return -EINVAL;

        return 0;
}
static int aoe_open ( struct interface parent,
struct uri uri 
) [static]

Open AoE URI.

Parameters:
parentParent interface
uriURI
Return values:
rcReturn status code

Definition at line 1014 of file aoe.c.

References aoe_parse_uri(), aoedev_open(), DBG, ENODEV, last_opened_netdev(), major, minor, netdev, and rc.

                                                                  {
        struct net_device *netdev;
        unsigned int major;
        unsigned int minor;
        int rc;

        /* Identify network device.  This is something of a hack, but
         * the AoE URI scheme that has been in use for some time now
         * provides no way to specify a particular device.
         */
        netdev = last_opened_netdev();
        if ( ! netdev ) {
                DBG ( "AoE cannot identify network device\n" );
                return -ENODEV;
        }

        /* Parse URI */
        if ( ( rc = aoe_parse_uri ( uri, &major, &minor ) ) != 0 ) {
                DBG ( "AoE cannot parse URI\n" );
                return rc;
        }

        /* Open AoE device */
        if ( ( rc = aoedev_open ( parent, netdev, major, minor ) ) != 0 )
                return rc;

        return 0;
}
static int abft_complete ( struct acpi_descriptor *desc  __unused) [static]

Check if AoE boot firmware table descriptor is complete.

Parameters:
descACPI descriptor
Return values:
rcReturn status code

Definition at line 1062 of file aoe.c.

                                                                   {
        return 0;
}
static int abft_install ( int(*)(struct acpi_header *acpi install) [static]

Install AoE boot firmware table(s)

Parameters:
installInstallation method
Return values:
rcReturn status code

Definition at line 1072 of file aoe.c.

References ABFT_SIG, abft_table::acpi, aoedev_name(), cpu_to_le16, cpu_to_le32, DBGC, acpi_header::length, list_for_each_entry, net_device::ll_addr, abft_table::mac, aoe_device::major, memcpy(), memset(), aoe_device::minor, aoe_device::netdev, rc, acpi_header::revision, abft_table::shelf, acpi_header::signature, abft_table::slot, and strerror().

                                                                           {
        struct aoe_device *aoedev;
        struct abft_table abft;
        int rc;

        list_for_each_entry ( aoedev, &abft_model.descs, desc.list ) {

                /* Populate table */
                memset ( &abft, 0, sizeof ( abft ) );
                abft.acpi.signature = cpu_to_le32 ( ABFT_SIG );
                abft.acpi.length = cpu_to_le32 ( sizeof ( abft ) );
                abft.acpi.revision = 1;
                abft.shelf = cpu_to_le16 ( aoedev->major );
                abft.slot = aoedev->minor;
                memcpy ( abft.mac, aoedev->netdev->ll_addr,
                         sizeof ( abft.mac ) );

                /* Install table */
                if ( ( rc = install ( &abft.acpi ) ) != 0 ) {
                        DBGC ( aoedev, "AoE %s could not install aBFT: %s\n",
                               aoedev_name ( aoedev ), strerror ( rc ) );
                        return rc;
                }
        }

        return 0;
}

Variable Documentation

struct net_protocol aoe_protocol __net_protocol
Initial value:
 {
        .name = "AoE",
        .net_proto = htons ( ETH_P_AOE ),
        .rx = aoe_rx,
}

AoE protocol.

Definition at line 55 of file aoe.c.

struct acpi_model abft_model __acpi_model
Initial value:
 {
        .descs = LIST_HEAD_INIT ( abft_model.descs ),
        .complete = abft_complete,
        .install = abft_install,
}

aBFT model

Definition at line 56 of file aoe.c.

struct aoe_command_type aoecmd_ata [static]
Initial value:
 {
        .cmd_len = aoecmd_ata_cmd_len,
        .cmd = aoecmd_ata_cmd,
        .rsp = aoecmd_ata_rsp,
}

AoE ATA command.

Definition at line 490 of file aoe.c.

struct aoe_command_type aoecmd_cfg [static]
Initial value:
 {
        .cmd_len = aoecmd_cfg_cmd_len,
        .cmd = aoecmd_cfg_cmd,
        .rsp = aoecmd_cfg_rsp,
}

AoE configuration command.

Definition at line 566 of file aoe.c.

Initial value:

AoE command ATA interface operations.

Definition at line 573 of file aoe.c.

Initial value:

AoE command ATA interface descriptor.

Definition at line 578 of file aoe.c.

Initial value:

AoE device ATA interface operations.

Definition at line 807 of file aoe.c.

Initial value:

AoE device ATA interface descriptor.

Definition at line 817 of file aoe.c.

Initial value:

AoE device configuration interface operations.

Definition at line 821 of file aoe.c.

Initial value:
        INTF_DESC ( struct aoe_device, config, aoedev_config_op )

AoE device configuration interface descriptor.

Definition at line 826 of file aoe.c.

struct uri_opener aoe_uri_opener __uri_opener
Initial value:
 {
        .scheme = "aoe",
        .open = aoe_open,
}

AoE URI opener.

Definition at line 1044 of file aoe.c.