From 43013da9bf02439b4726d8afef15f7ce97d1c469 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 29 Jul 2007 02:31:14 +0100 Subject: [PATCH] Quick hack to get AoE back in to the tree, on a par with the current iSCSI hack. --- src/drivers/ata/aoedev.c | 55 ---------------- src/include/gpxe/aoe.h | 25 +++----- src/include/gpxe/ata.h | 3 + src/include/usr/aoeboot.h | 6 ++ src/net/aoe.c | 130 ++++++++++++++++++++++++++++---------- src/tests/aoeboot.c | 71 --------------------- src/usr/aoeboot.c | 67 ++++++++++++++++++++ src/usr/autoboot.c | 11 ++-- 8 files changed, 187 insertions(+), 181 deletions(-) delete mode 100644 src/drivers/ata/aoedev.c create mode 100644 src/include/usr/aoeboot.h delete mode 100644 src/tests/aoeboot.c create mode 100644 src/usr/aoeboot.c diff --git a/src/drivers/ata/aoedev.c b/src/drivers/ata/aoedev.c deleted file mode 100644 index ff047f10..00000000 --- a/src/drivers/ata/aoedev.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2006 Michael Brown . - * - * 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. - */ - -#include -#include -#include - -/** @file - * - * AoE ATA device - * - */ - -/** - * Issue ATA command via AoE device - * - * @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_device *aoedev - = container_of ( ata, struct aoe_device, ata ); - struct async async; - - return async_block ( &async, aoe_issue ( &aoedev->aoe, command, - &async ) ); -} - -/** - * Initialise AoE device - * - * @v aoedev AoE device - */ -int init_aoedev ( struct aoe_device *aoedev ) { - aoedev->ata.command = aoe_command; - aoe_open ( &aoedev->aoe ); - return init_atadev ( &aoedev->ata ); -} diff --git a/src/include/gpxe/aoe.h b/src/include/gpxe/aoe.h index eb5e1133..85683384 100644 --- a/src/include/gpxe/aoe.h +++ b/src/include/gpxe/aoe.h @@ -81,6 +81,9 @@ struct aoehdr { /** An AoE session */ struct aoe_session { + /** Reference counter */ + struct refcnt refcnt; + /** List of all AoE sessions */ struct list_head list; @@ -103,8 +106,8 @@ struct aoe_session { unsigned int status; /** Byte offset within command's data buffer */ unsigned int command_offset; - /** Asynchronous operation for this command */ - struct async async; + /** Return status code for command */ + int rc; /** Retransmission timer */ struct retry_timer timer; @@ -116,20 +119,8 @@ struct aoe_session { /** Maximum number of sectors per packet */ #define AOE_MAX_COUNT 2 -extern void aoe_open ( struct aoe_session *aoe ); -extern void aoe_close ( struct aoe_session *aoe ); -extern int aoe_issue ( struct aoe_session *aoe, - struct ata_command *command, - struct async *parent ); - -/** An AoE device */ -struct aoe_device { - /** ATA device interface */ - struct ata_device ata; - /** AoE protocol instance */ - struct aoe_session aoe; -}; - -extern int init_aoedev ( struct aoe_device *aoedev ); +extern void aoe_detach ( struct ata_device *ata ); +extern int aoe_attach ( struct ata_device *ata, struct net_device *netdev, + const char *root_path ); #endif /* _GPXE_AOE_H */ diff --git a/src/include/gpxe/ata.h b/src/include/gpxe/ata.h index e0fca7af..b6da3930 100644 --- a/src/include/gpxe/ata.h +++ b/src/include/gpxe/ata.h @@ -4,6 +4,7 @@ #include #include #include +#include /** @file * @@ -195,6 +196,8 @@ struct ata_device { */ int ( * command ) ( struct ata_device *ata, struct ata_command *command ); + /** Backing device */ + struct refcnt *backend; }; extern int init_atadev ( struct ata_device *ata ); diff --git a/src/include/usr/aoeboot.h b/src/include/usr/aoeboot.h new file mode 100644 index 00000000..0421ebcc --- /dev/null +++ b/src/include/usr/aoeboot.h @@ -0,0 +1,6 @@ +#ifndef _USR_AOEBOOT_H +#define _USR_AOEBOOT_H + +extern int aoeboot ( const char *root_path ); + +#endif /* _USR_AOEBOOT_H */ diff --git a/src/net/aoe.c b/src/net/aoe.c index 36721df6..fd82665d 100644 --- a/src/net/aoe.c +++ b/src/net/aoe.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -29,7 +30,7 @@ #include #include #include -#include +#include #include /** @file @@ -43,6 +44,14 @@ 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 * @@ -55,8 +64,8 @@ static void aoe_done ( struct aoe_session *aoe, int rc ) { aoe->command->cb.cmd_stat = aoe->status; aoe->command = NULL; - /* Mark async operation as complete */ - async_done ( &aoe->async, rc ); + /* Mark operation as complete */ + aoe->rc = rc; } /** @@ -265,46 +274,99 @@ struct net_protocol aoe_protocol __net_protocol = { .rx = aoe_rx, }; -/** - * Open AoE session - * - * @v aoe AoE session - */ -void aoe_open ( struct aoe_session *aoe ) { - memcpy ( aoe->target, ethernet_protocol.ll_broadcast, - sizeof ( aoe->target ) ); - aoe->tag = AOE_TAG_MAGIC; - aoe->timer.expired = aoe_timer_expired; - list_add ( &aoe->list, &aoe_sessions ); -} - -/** - * Close AoE session - * - * @v aoe AoE session - */ -void aoe_close ( struct aoe_session *aoe ) { - list_del ( &aoe->list ); -} - /** * Issue ATA command via an open AoE session * - * @v aoe AoE session + * @v ata ATA device * @v command ATA command - * @v parent Parent asynchronous operation * @ret rc Return status code - * - * Only one command may be issued concurrently per session. This call - * is non-blocking; use async_wait() to wait for the command to - * complete. */ -int aoe_issue ( struct aoe_session *aoe, struct ata_command *command, - struct async *parent ) { +static int aoe_command ( struct ata_device *ata, + struct ata_command *command ) { + struct aoe_session *aoe = + container_of ( ata->backend, struct aoe_session, refcnt ); + int rc; + aoe->command = command; aoe->status = 0; aoe->command_offset = 0; aoe_send_command ( aoe ); - async_init ( &aoe->async, &default_async_operations, parent ); + + 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, ethernet_protocol.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 ); + return 0; + + err: + ref_put ( &aoe->refcnt ); + return rc; +} diff --git a/src/tests/aoeboot.c b/src/tests/aoeboot.c deleted file mode 100644 index 17fda2c6..00000000 --- a/src/tests/aoeboot.c +++ /dev/null @@ -1,71 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -static struct aoe_device test_aoedev = { - .aoe = { - .major = 0, - .minor = 0, - }, -}; - -static int aoe_parse ( const char *aoename, struct aoe_session *aoe ) { - char *ptr = ( ( char * ) aoename ); - - 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 test_aoeboot ( struct net_device *netdev, const char *aoename, - unsigned int drivenum ) { - struct int13_drive drive; - int rc; - - printf ( "Attempting to boot from AoE device %s via %s\n", - aoename, netdev->name ); - - if ( ( rc = aoe_parse ( aoename, &test_aoedev.aoe ) ) != 0 ) { - printf ( "Invalid AoE device name \"%s\"\n", aoename ); - return rc; - } - - printf ( "Initialising AoE device e%d.%d\n", - test_aoedev.aoe.major, test_aoedev.aoe.minor ); - test_aoedev.aoe.netdev = netdev; - if ( ( rc = init_aoedev ( &test_aoedev ) ) != 0 ) { - printf ( "Could not reach AoE device e%d.%d\n", - test_aoedev.aoe.major, test_aoedev.aoe.minor ); - return rc; - } - - memset ( &drive, 0, sizeof ( drive ) ); - drive.drive = drivenum; - drive.blockdev = &test_aoedev.ata.blockdev; - register_int13_drive ( &drive ); - printf ( "Registered AoE device e%d.%d as BIOS drive %#02x\n", - test_aoedev.aoe.major, test_aoedev.aoe.minor, drive.drive ); - - printf ( "Booting from BIOS drive %#02x\n", drive.drive ); - rc = int13_boot ( drive.drive ); - printf ( "Boot failed\n" ); - - printf ( "Unregistering BIOS drive %#02x\n", drive.drive ); - unregister_int13_drive ( &drive ); - - return rc; -} diff --git a/src/usr/aoeboot.c b/src/usr/aoeboot.c new file mode 100644 index 00000000..54bb5d47 --- /dev/null +++ b/src/usr/aoeboot.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Guess boot network device + * + * @ret netdev Boot network device + */ +static struct net_device * guess_boot_netdev ( void ) { + struct net_device *boot_netdev; + + /* Just use the first network device */ + for_each_netdev ( boot_netdev ) { + return boot_netdev; + } + + return NULL; +} + +int aoeboot ( const char *root_path ) { + struct ata_device ata; + struct int13_drive drive; + int rc; + + memset ( &ata, 0, sizeof ( ata ) ); + memset ( &drive, 0, sizeof ( drive ) ); + + printf ( "AoE booting from %s\n", root_path ); + + /* FIXME: ugly, ugly hack */ + struct net_device *netdev = guess_boot_netdev(); + + if ( ( rc = aoe_attach ( &ata, netdev, root_path ) ) != 0 ) { + printf ( "Could not attach AoE device: %s\n", + strerror ( rc ) ); + goto error_attach; + } + if ( ( rc = init_atadev ( &ata ) ) != 0 ) { + printf ( "Could not initialise AoE device: %s\n", + strerror ( rc ) ); + goto error_init; + } + + drive.drive = find_global_dhcp_num_option ( DHCP_EB_BIOS_DRIVE ); + drive.blockdev = &ata.blockdev; + + register_int13_drive ( &drive ); + printf ( "Registered as BIOS drive %#02x\n", drive.drive ); + printf ( "Booting from BIOS drive %#02x\n", drive.drive ); + rc = int13_boot ( drive.drive ); + printf ( "Boot failed\n" ); + + printf ( "Unregistering BIOS drive %#02x\n", drive.drive ); + unregister_int13_drive ( &drive ); + + error_init: + aoe_detach ( &ata ); + error_attach: + return rc; +} diff --git a/src/usr/autoboot.c b/src/usr/autoboot.c index 4bc43d5a..53283d18 100644 --- a/src/usr/autoboot.c +++ b/src/usr/autoboot.c @@ -27,6 +27,7 @@ #include #include #include +#include #include /** @file @@ -88,13 +89,15 @@ static int boot_filename ( const char *filename ) { * @ret rc Return status code */ static int boot_root_path ( const char *root_path ) { - int rc; /* Quick hack */ - if ( ( rc = iscsiboot ( root_path ) ) != 0 ) - return rc; + if ( strncmp ( root_path, "iscsi:", 6 ) == 0 ) { + return iscsiboot ( root_path ); + } else if ( strncmp ( root_path, "aoe:", 4 ) == 0 ) { + return aoeboot ( root_path ); + } - return 0; + return -ENOTSUP; } /**