david/ipxe
Archived
1
0

Quick hack to get AoE back in to the tree, on a par with the current

iSCSI hack.
This commit is contained in:
Michael Brown 2007-07-29 02:31:14 +01:00
parent a6a1052096
commit 43013da9bf
8 changed files with 187 additions and 181 deletions

View File

@ -1,55 +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.
*/
#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 );
}

View File

@ -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 */

View File

@ -4,6 +4,7 @@
#include <stdint.h>
#include <gpxe/blockdev.h>
#include <gpxe/uaccess.h>
#include <gpxe/refcnt.h>
/** @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 );

View File

@ -0,0 +1,6 @@
#ifndef _USR_AOEBOOT_H
#define _USR_AOEBOOT_H
extern int aoeboot ( const char *root_path );
#endif /* _USR_AOEBOOT_H */

View File

@ -19,6 +19,7 @@
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <byteswap.h>
@ -29,7 +30,7 @@
#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
@ -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;
}

View File

@ -1,71 +0,0 @@
#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;
}

67
src/usr/aoeboot.c Normal file
View File

@ -0,0 +1,67 @@
#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;
}

View File

@ -27,6 +27,7 @@
#include <usr/dhcpmgmt.h>
#include <usr/imgmgmt.h>
#include <usr/iscsiboot.h>
#include <usr/aoeboot.h>
#include <usr/autoboot.h>
/** @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;
}
/**