iSCSI hack.
+++ /dev/null
-/*
- * 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.
- */
-
-#include <stddef.h>
-#include <gpxe/async.h>
-#include <gpxe/aoe.h>
-
-/** @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 );
-}
/** An AoE session */
struct aoe_session {
+ /** Reference counter */
+ struct refcnt refcnt;
+
/** List of all AoE sessions */
struct list_head list;
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;
/** 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 */
#include <stdint.h>
#include <gpxe/blockdev.h>
#include <gpxe/uaccess.h>
+#include <gpxe/refcnt.h>
/** @file
*
*/
int ( * command ) ( struct ata_device *ata,
struct ata_command *command );
+ /** Backing device */
+ struct refcnt *backend;
};
extern int init_atadev ( struct ata_device *ata );
--- /dev/null
+#ifndef _USR_AOEBOOT_H
+#define _USR_AOEBOOT_H
+
+extern int aoeboot ( const char *root_path );
+
+#endif /* _USR_AOEBOOT_H */
#include <stddef.h>
#include <string.h>
#include <stdio.h>
+#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <byteswap.h>
#include <gpxe/uaccess.h>
#include <gpxe/ata.h>
#include <gpxe/netdevice.h>
-#include <gpxe/async.h>
+#include <gpxe/process.h>
#include <gpxe/aoe.h>
/** @file
/** 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
*
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;
}
/**
.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;
+}
+++ /dev/null
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <console.h>
-#include <gpxe/netdevice.h>
-#include <gpxe/aoe.h>
-#include <int13.h>
-
-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;
-}
--- /dev/null
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <gpxe/aoe.h>
+#include <gpxe/ata.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/dhcp.h>
+#include <int13.h>
+#include <usr/aoeboot.h>
+
+/**
+ * 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;
+}
#include <usr/dhcpmgmt.h>
#include <usr/imgmgmt.h>
#include <usr/iscsiboot.h>
+#include <usr/aoeboot.h>
#include <usr/autoboot.h>
/** @file
* @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;
}
/**