diff options
Diffstat (limited to 'gpxe/src/net/aoe.c')
-rw-r--r-- | gpxe/src/net/aoe.c | 471 |
1 files changed, 0 insertions, 471 deletions
diff --git a/gpxe/src/net/aoe.c b/gpxe/src/net/aoe.c deleted file mode 100644 index 839a875b..00000000 --- a/gpxe/src/net/aoe.c +++ /dev/null @@ -1,471 +0,0 @@ -/* - * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include <stddef.h> -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <assert.h> -#include <byteswap.h> -#include <gpxe/list.h> -#include <gpxe/if_ether.h> -#include <gpxe/ethernet.h> -#include <gpxe/iobuf.h> -#include <gpxe/uaccess.h> -#include <gpxe/ata.h> -#include <gpxe/netdevice.h> -#include <gpxe/process.h> -#include <gpxe/features.h> -#include <gpxe/aoe.h> - -/** @file - * - * AoE protocol - * - */ - -FEATURE ( FEATURE_PROTOCOL, "AoE", DHCP_EB_FEATURE_AOE, 1 ); - -struct net_protocol aoe_protocol; - -/** List of all AoE sessions */ -static LIST_HEAD ( aoe_sessions ); - -static void aoe_free ( struct refcnt *refcnt ) { - struct aoe_session *aoe = - container_of ( refcnt, struct aoe_session, refcnt ); - - netdev_put ( aoe->netdev ); - free ( aoe ); -} - -/** - * Mark current AoE command complete - * - * @v aoe AoE session - * @v rc Return status code - */ -static void aoe_done ( struct aoe_session *aoe, int rc ) { - - /* Record overall command status */ - if ( aoe->command ) { - aoe->command->cb.cmd_stat = aoe->status; - aoe->command->rc = rc; - aoe->command = NULL; - } - - /* Stop retransmission timer */ - stop_timer ( &aoe->timer ); - - /* Mark operation as complete */ - aoe->rc = rc; -} - -/** - * Send AoE command - * - * @v aoe AoE session - * @ret rc Return status code - * - * This transmits an AoE command packet. It does not wait for a - * response. - */ -static int aoe_send_command ( struct aoe_session *aoe ) { - struct ata_command *command = aoe->command; - struct io_buffer *iobuf; - struct aoehdr *aoehdr; - union aoecmd *aoecmd; - struct aoeata *aoeata; - unsigned int count; - unsigned int data_out_len; - unsigned int aoecmdlen; - - /* Fail immediately if we have no netdev to send on */ - if ( ! aoe->netdev ) { - aoe_done ( aoe, -ENETUNREACH ); - return -ENETUNREACH; - } - - /* 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 ( &aoe->timer ); - - /* Calculate count and data_out_len for this subcommand */ - switch ( aoe->aoe_cmd_type ) { - case AOE_CMD_ATA: - count = command->cb.count.native; - if ( count > AOE_MAX_COUNT ) - count = AOE_MAX_COUNT; - data_out_len = ( command->data_out ? - ( count * ATA_SECTOR_SIZE ) : 0 ); - aoecmdlen = sizeof ( aoecmd->ata ); - break; - case AOE_CMD_CONFIG: - count = 0; - data_out_len = 0; - aoecmdlen = sizeof ( aoecmd->cfg ); - break; - default: - return -ENOTSUP; - } - - /* Create outgoing I/O buffer */ - iobuf = alloc_iob ( ETH_HLEN + sizeof ( *aoehdr ) + - aoecmdlen + data_out_len ); - - if ( ! iobuf ) - return -ENOMEM; - iob_reserve ( iobuf, ETH_HLEN ); - aoehdr = iob_put ( iobuf, sizeof ( *aoehdr ) ); - aoecmd = iob_put ( iobuf, aoecmdlen ); - memset ( aoehdr, 0, ( sizeof ( *aoehdr ) + aoecmdlen ) ); - - /* Fill AoE header */ - aoehdr->ver_flags = AOE_VERSION; - aoehdr->major = htons ( aoe->major ); - aoehdr->minor = aoe->minor; - aoehdr->command = aoe->aoe_cmd_type; - aoehdr->tag = htonl ( ++aoe->tag ); - - /* Fill AoE payload */ - switch ( aoe->aoe_cmd_type ) { - case AOE_CMD_ATA: - /* Fill AoE command */ - aoeata = &aoecmd->ata; - linker_assert ( AOE_FL_DEV_HEAD == ATA_DEV_SLAVE, - __fix_ata_h__ ); - aoeata->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 )| - ( command->cb.device & ATA_DEV_SLAVE ) | - ( data_out_len ? AOE_FL_WRITE : 0 ) ); - aoeata->err_feat = command->cb.err_feat.bytes.cur; - aoeata->count = count; - 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 ); - - /* Fill data payload */ - copy_from_user ( iob_put ( iobuf, data_out_len ), - command->data_out, aoe->command_offset, - data_out_len ); - break; - case AOE_CMD_CONFIG: - /* Nothing to do */ - break; - default: - assert ( 0 ); - } - - /* Send packet */ - return net_tx ( iobuf, aoe->netdev, &aoe_protocol, aoe->target ); -} - -/** - * Handle AoE retry timer expiry - * - * @v timer AoE retry timer - * @v fail Failure indicator - */ -static void aoe_timer_expired ( struct retry_timer *timer, int fail ) { - struct aoe_session *aoe = - container_of ( timer, struct aoe_session, timer ); - - if ( fail ) { - aoe_done ( aoe, -ETIMEDOUT ); - } else { - aoe_send_command ( aoe ); - } -} - -/** - * Handle AoE configuration command response - * - * @v aoe AoE session - * @v ll_source Link-layer source address - * @ret rc Return status code - */ -static int aoe_rx_cfg ( struct aoe_session *aoe, const void *ll_source ) { - - /* Record target MAC address */ - memcpy ( aoe->target, ll_source, sizeof ( aoe->target ) ); - DBGC ( aoe, "AoE %p target MAC address %s\n", - aoe, eth_ntoa ( aoe->target ) ); - - /* Mark config request as complete */ - aoe_done ( aoe, 0 ); - - return 0; -} - -/** - * Handle AoE ATA command response - * - * @v aoe AoE session - * @v aoeata AoE ATA command - * @v len Length of AoE ATA command - * @ret rc Return status code - */ -static int aoe_rx_ata ( struct aoe_session *aoe, struct aoeata *aoeata, - size_t len ) { - struct ata_command *command = aoe->command; - unsigned int rx_data_len; - unsigned int count; - unsigned int data_len; - - /* Sanity check */ - if ( len < sizeof ( *aoeata ) ) { - /* Ignore packet; allow timer to trigger retransmit */ - return -EINVAL; - } - rx_data_len = ( len - sizeof ( *aoeata ) ); - - /* Calculate count and data_len for this subcommand */ - count = command->cb.count.native; - if ( count > AOE_MAX_COUNT ) - count = AOE_MAX_COUNT; - data_len = count * ATA_SECTOR_SIZE; - - /* Merge into overall ATA status */ - aoe->status |= aoeata->cmd_stat; - - /* Copy data payload */ - if ( command->data_in ) { - if ( rx_data_len > data_len ) - rx_data_len = data_len; - copy_to_user ( command->data_in, aoe->command_offset, - aoeata->data, rx_data_len ); - } - - /* Update ATA command and offset */ - aoe->command_offset += data_len; - command->cb.lba.native += count; - command->cb.count.native -= count; - - /* Check for operation complete */ - if ( ! command->cb.count.native ) { - aoe_done ( aoe, 0 ); - return 0; - } - - /* Transmit next portion of request */ - stop_timer ( &aoe->timer ); - aoe_send_command ( aoe ); - - return 0; -} - -/** - * Process incoming AoE packets - * - * @v iobuf I/O buffer - * @v netdev Network device - * @v ll_source Link-layer source address - * @ret rc Return status code - * - */ -static int aoe_rx ( struct io_buffer *iobuf, - struct net_device *netdev __unused, - const void *ll_source ) { - struct aoehdr *aoehdr = iobuf->data; - struct aoe_session *aoe; - int rc = 0; - - /* Sanity checks */ - if ( iob_len ( iobuf ) < sizeof ( *aoehdr ) ) { - rc = -EINVAL; - goto done; - } - if ( ( aoehdr->ver_flags & AOE_VERSION_MASK ) != AOE_VERSION ) { - rc = -EPROTONOSUPPORT; - goto done; - } - if ( ! ( aoehdr->ver_flags & AOE_FL_RESPONSE ) ) { - /* Ignore AoE requests that we happen to see */ - goto done; - } - iob_pull ( iobuf, sizeof ( *aoehdr ) ); - - /* Demultiplex amongst active AoE sessions */ - list_for_each_entry ( aoe, &aoe_sessions, list ) { - if ( ntohs ( aoehdr->major ) != aoe->major ) - continue; - if ( aoehdr->minor != aoe->minor ) - continue; - if ( ntohl ( aoehdr->tag ) != aoe->tag ) - continue; - if ( aoehdr->ver_flags & AOE_FL_ERROR ) { - aoe_done ( aoe, -EIO ); - break; - } - switch ( aoehdr->command ) { - case AOE_CMD_ATA: - rc = aoe_rx_ata ( aoe, iobuf->data, iob_len ( iobuf )); - break; - case AOE_CMD_CONFIG: - rc = aoe_rx_cfg ( aoe, ll_source ); - break; - default: - DBGC ( aoe, "AoE %p ignoring command %02x\n", - aoe, aoehdr->command ); - break; - } - break; - } - - done: - free_iob ( iobuf ); - return rc; -} - -/** AoE protocol */ -struct net_protocol aoe_protocol __net_protocol = { - .name = "AoE", - .net_proto = htons ( ETH_P_AOE ), - .rx = aoe_rx, -}; - -/** - * Issue ATA command via an open AoE session - * - * @v ata ATA device - * @v command ATA command - * @ret rc Return status code - */ -static int aoe_command ( struct ata_device *ata, - struct ata_command *command ) { - struct aoe_session *aoe = - container_of ( ata->backend, struct aoe_session, refcnt ); - - aoe->command = command; - aoe->status = 0; - aoe->command_offset = 0; - aoe->aoe_cmd_type = AOE_CMD_ATA; - - aoe_send_command ( aoe ); - - return 0; -} - -/** - * Issue AoE config query for AoE target discovery - * - * @v aoe AoE session - * @ret rc Return status code - */ -static int aoe_discover ( struct aoe_session *aoe ) { - int rc; - - aoe->status = 0; - aoe->aoe_cmd_type = AOE_CMD_CONFIG; - aoe->command = NULL; - - aoe_send_command ( aoe ); - - aoe->rc = -EINPROGRESS; - while ( aoe->rc == -EINPROGRESS ) - step(); - rc = aoe->rc; - - return rc; -} - -static int aoe_detached_command ( struct ata_device *ata __unused, - struct ata_command *command __unused ) { - return -ENODEV; -} - -void aoe_detach ( struct ata_device *ata ) { - struct aoe_session *aoe = - container_of ( ata->backend, struct aoe_session, refcnt ); - - stop_timer ( &aoe->timer ); - ata->command = aoe_detached_command; - list_del ( &aoe->list ); - ref_put ( ata->backend ); - ata->backend = NULL; -} - -static int aoe_parse_root_path ( struct aoe_session *aoe, - const char *root_path ) { - char *ptr; - - if ( strncmp ( root_path, "aoe:", 4 ) != 0 ) - return -EINVAL; - ptr = ( ( char * ) root_path + 4 ); - - if ( *ptr++ != 'e' ) - return -EINVAL; - - aoe->major = strtoul ( ptr, &ptr, 10 ); - if ( *ptr++ != '.' ) - return -EINVAL; - - aoe->minor = strtoul ( ptr, &ptr, 10 ); - if ( *ptr ) - return -EINVAL; - - return 0; -} - -int aoe_attach ( struct ata_device *ata, struct net_device *netdev, - const char *root_path ) { - struct aoe_session *aoe; - int rc; - - /* Allocate and initialise structure */ - aoe = zalloc ( sizeof ( *aoe ) ); - if ( ! aoe ) - return -ENOMEM; - aoe->refcnt.free = aoe_free; - aoe->netdev = netdev_get ( netdev ); - memcpy ( aoe->target, netdev->ll_broadcast, sizeof ( aoe->target ) ); - aoe->tag = AOE_TAG_MAGIC; - aoe->timer.expired = aoe_timer_expired; - - /* Parse root path */ - if ( ( rc = aoe_parse_root_path ( aoe, root_path ) ) != 0 ) - goto err; - - /* Attach parent interface, transfer reference to connection - * list, and return - */ - ata->backend = ref_get ( &aoe->refcnt ); - ata->command = aoe_command; - list_add ( &aoe->list, &aoe_sessions ); - - /* Send discovery packet to find the target MAC address. - * Ideally, this ought to be done asynchronously, but the - * block device interface does not yet support asynchronous - * operation. - */ - if ( ( rc = aoe_discover( aoe ) ) != 0 ) - goto err; - - return 0; - - err: - ref_put ( &aoe->refcnt ); - return rc; -} |