david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[block] Add basic multipath support

Add basic support for multipath block devices.  The "sanboot" and
"sanhook" commands now accept a list of SAN URIs.  We open all URIs
concurrently.  The first connection to become available for issuing
block device commands is marked as the active path and used for all
subsequent commands; all other connections are then closed.  Whenever
the active path fails, we reopen all URIs and repeat the process.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown 2017-03-26 15:12:11 +03:00
parent c212597336
commit bb5a54b79a
10 changed files with 327 additions and 128 deletions

View File

@ -833,6 +833,7 @@ static int int13_extended_seek ( struct san_device *sandev,
*/
static int int13_device_path_info ( struct san_device *sandev,
struct edd_device_path_information *dpi ) {
struct san_path *sanpath;
struct device *device;
struct device_description *desc;
unsigned int i;
@ -843,9 +844,11 @@ static int int13_device_path_info ( struct san_device *sandev,
if ( sandev_needs_reopen ( sandev ) &&
( ( rc = sandev_reopen ( sandev ) ) != 0 ) )
return rc;
sanpath = sandev->active;
assert ( sanpath != NULL );
/* Get underlying hardware device */
device = identify_device ( &sandev->block );
device = identify_device ( &sanpath->block );
if ( ! device ) {
DBGC ( sandev, "INT13 drive %02x cannot identify hardware "
"device\n", sandev->drive );
@ -869,7 +872,7 @@ static int int13_device_path_info ( struct san_device *sandev,
}
/* Get EDD block device description */
if ( ( rc = edd_describe ( &sandev->block, &dpi->interface_type,
if ( ( rc = edd_describe ( &sanpath->block, &dpi->interface_type,
&dpi->device_path ) ) != 0 ) {
DBGC ( sandev, "INT13 drive %02x cannot identify block device: "
"%s\n", sandev->drive, strerror ( rc ) );
@ -1199,14 +1202,16 @@ static void int13_unhook_vector ( void ) {
/**
* Hook INT 13 SAN device
*
* @v uri URI
* @v drive Drive number
* @v uris List of URIs
* @v count Number of URIs
* @ret drive Drive number, or negative error
*
* Registers the drive with the INT 13 emulation subsystem, and hooks
* the INT 13 interrupt vector (if not already hooked).
*/
static int int13_hook ( struct uri *uri, unsigned int drive ) {
static int int13_hook ( unsigned int drive, struct uri **uris,
unsigned int count ) {
struct san_device *sandev;
struct int13_data *int13;
unsigned int natural_drive;
@ -1223,7 +1228,7 @@ static int int13_hook ( struct uri *uri, unsigned int drive ) {
drive = natural_drive;
/* Allocate SAN device */
sandev = alloc_sandev ( uri, sizeof ( *int13 ) );
sandev = alloc_sandev ( uris, count, sizeof ( *int13 ) );
if ( ! sandev ) {
rc = -ENOMEM;
goto err_alloc;
@ -1525,6 +1530,7 @@ static union xbft_table __bss16 ( xbftab ) __attribute__ (( aligned ( 16 ) ));
*/
static int int13_describe ( unsigned int drive ) {
struct san_device *sandev;
struct san_path *sanpath;
struct segoff xbft_address;
int rc;
@ -1539,6 +1545,8 @@ static int int13_describe ( unsigned int drive ) {
if ( sandev_needs_reopen ( sandev ) &&
( ( rc = sandev_reopen ( sandev ) ) != 0 ) )
return rc;
sanpath = sandev->active;
assert ( sanpath != NULL );
/* Clear table */
memset ( &xbftab, 0, sizeof ( xbftab ) );
@ -1550,7 +1558,7 @@ static int int13_describe ( unsigned int drive ) {
sizeof ( xbftab.acpi.oem_table_id ) );
/* Fill in remaining parameters */
if ( ( rc = acpi_describe ( &sandev->block, &xbftab.acpi,
if ( ( rc = acpi_describe ( &sanpath->block, &xbftab.acpi,
sizeof ( xbftab ) ) ) != 0 ) {
DBGC ( sandev, "INT13 drive %02x could not create ACPI "
"description: %s\n", sandev->drive, strerror ( rc ) );

View File

@ -35,16 +35,18 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* Hook dummy SAN device
*
* @v uri URI
* @v drive Drive number
* @v uris List of URIs
* @v count Number of URIs
* @ret drive Drive number, or negative error
*/
static int dummy_san_hook ( struct uri *uri, unsigned int drive ) {
static int dummy_san_hook ( unsigned int drive, struct uri **uris,
unsigned int count ) {
struct san_device *sandev;
int rc;
/* Allocate SAN device */
sandev = alloc_sandev ( uri, 0 );
sandev = alloc_sandev ( uris, count, 0 );
if ( ! sandev ) {
rc = -ENOMEM;
goto err_alloc;

View File

@ -26,8 +26,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <errno.h>
#include <ipxe/sanboot.h>
static int null_san_hook ( struct uri *uri __unused,
unsigned int drive __unused ) {
static int null_san_hook ( unsigned int drive __unused,
struct uri **uris __unused,
unsigned int count __unused ) {
return -EOPNOTSUPP;
}

View File

@ -101,9 +101,13 @@ struct san_device * sandev_find ( unsigned int drive ) {
static void sandev_free ( struct refcnt *refcnt ) {
struct san_device *sandev =
container_of ( refcnt, struct san_device, refcnt );
struct san_path *sanpath;
assert ( ! timer_running ( &sandev->timer ) );
uri_put ( sandev->uri );
assert ( ! sandev->active );
assert ( list_empty ( &sandev->opened ) );
list_for_each_entry ( sanpath, &sandev->closed, list )
uri_put ( sanpath->uri );
free ( sandev );
}
@ -162,6 +166,143 @@ static void sandev_command_expired ( struct retry_timer *timer,
sandev_command_close ( sandev, -ETIMEDOUT );
}
/**
* Open SAN path
*
* @v sanpath SAN path
* @ret rc Return status code
*/
static int sanpath_open ( struct san_path *sanpath ) {
struct san_device *sandev = sanpath->sandev;
int rc;
/* Sanity check */
list_check_contains_entry ( sanpath, &sandev->closed, list );
/* Open interface */
if ( ( rc = xfer_open_uri ( &sanpath->block, sanpath->uri ) ) != 0 ) {
DBGC ( sandev, "SAN %#02x.%d could not (re)open URI: "
"%s\n", sandev->drive, sanpath->index, strerror ( rc ) );
return rc;
}
/* Start process */
process_add ( &sanpath->process );
/* Mark as opened */
list_del ( &sanpath->list );
list_add_tail ( &sanpath->list, &sandev->opened );
/* Record as in progress */
sanpath->path_rc = -EINPROGRESS;
return 0;
}
/**
* Close SAN path
*
* @v sanpath SAN path
* @v rc Reason for close
*/
static void sanpath_close ( struct san_path *sanpath, int rc ) {
struct san_device *sandev = sanpath->sandev;
/* Record status */
sanpath->path_rc = rc;
/* Mark as closed */
list_del ( &sanpath->list );
list_add_tail ( &sanpath->list, &sandev->closed );
/* Stop process */
process_del ( &sanpath->process );
/* Restart interfaces, avoiding potential loops */
if ( sanpath == sandev->active ) {
intfs_restart ( rc, &sandev->command, &sanpath->block, NULL );
sandev->active = NULL;
sandev_command_close ( sandev, rc );
} else {
intf_restart ( &sanpath->block, rc );
}
}
/**
* Handle closure of underlying block device interface
*
* @v sanpath SAN path
* @v rc Reason for close
*/
static void sanpath_block_close ( struct san_path *sanpath, int rc ) {
struct san_device *sandev = sanpath->sandev;
/* Any closure is an error from our point of view */
if ( rc == 0 )
rc = -ENOTCONN;
DBGC ( sandev, "SAN %#02x.%d closed: %s\n",
sandev->drive, sanpath->index, strerror ( rc ) );
/* Close path */
sanpath_close ( sanpath, rc );
}
/**
* Check flow control window
*
* @v sanpath SAN path
*/
static size_t sanpath_block_window ( struct san_path *sanpath __unused ) {
/* We are never ready to receive data via this interface.
* This prevents objects that support both block and stream
* interfaces from attempting to send us stream data.
*/
return 0;
}
/**
* SAN path process
*
* @v sanpath SAN path
*/
static void sanpath_step ( struct san_path *sanpath ) {
struct san_device *sandev = sanpath->sandev;
/* Wait until path has become available */
if ( ! xfer_window ( &sanpath->block ) )
return;
/* Record status */
sanpath->path_rc = 0;
/* Mark as active path or close as applicable */
if ( ! sandev->active ) {
DBGC ( sandev, "SAN %#02x.%d is active\n",
sandev->drive, sanpath->index );
sandev->active = sanpath;
} else {
DBGC ( sandev, "SAN %#02x.%d is available\n",
sandev->drive, sanpath->index );
sanpath_close ( sanpath, 0 );
}
}
/** SAN path block interface operations */
static struct interface_operation sanpath_block_op[] = {
INTF_OP ( intf_close, struct san_path *, sanpath_block_close ),
INTF_OP ( xfer_window, struct san_path *, sanpath_block_window ),
INTF_OP ( xfer_window_changed, struct san_path *, sanpath_step ),
};
/** SAN path block interface descriptor */
static struct interface_descriptor sanpath_block_desc =
INTF_DESC ( struct san_path, block, sanpath_block_op );
/** SAN path process descriptor */
static struct process_descriptor sanpath_process_desc =
PROC_DESC_ONCE ( struct san_path, process, sanpath_step );
/**
* Restart SAN device interface
*
@ -169,15 +310,19 @@ static void sandev_command_expired ( struct retry_timer *timer,
* @v rc Reason for restart
*/
static void sandev_restart ( struct san_device *sandev, int rc ) {
struct san_path *sanpath;
/* Restart block device interface */
intfs_restart ( rc, &sandev->command, &sandev->block, NULL );
/* Restart all block device interfaces */
while ( ( sanpath = list_first_entry ( &sandev->opened,
struct san_path, list ) ) ) {
sanpath_close ( sanpath, rc );
}
/* Clear active path */
sandev->active = NULL;
/* Close any outstanding command */
sandev_command_close ( sandev, rc );
/* Record device error */
sandev->block_rc = rc;
}
/**
@ -189,77 +334,53 @@ static void sandev_restart ( struct san_device *sandev, int rc ) {
* This function will block until the device is available.
*/
int sandev_reopen ( struct san_device *sandev ) {
struct san_path *sanpath;
int rc;
/* Close any outstanding command and restart interface */
/* Close any outstanding command and restart interfaces */
sandev_restart ( sandev, -ECONNRESET );
assert ( sandev->active == NULL );
assert ( list_empty ( &sandev->opened ) );
/* Mark device as being not yet open */
sandev->block_rc = -EINPROGRESS;
/* Open block device interface */
if ( ( rc = xfer_open_uri ( &sandev->block, sandev->uri ) ) != 0 ) {
DBGC ( sandev, "SAN %#02x could not (re)open URI: %s\n",
sandev->drive, strerror ( rc ) );
return rc;
/* Open all paths */
while ( ( sanpath = list_first_entry ( &sandev->closed,
struct san_path, list ) ) ) {
if ( ( rc = sanpath_open ( sanpath ) ) != 0 )
goto err_open;
}
/* Wait for device to become available */
while ( sandev->block_rc == -EINPROGRESS ) {
/* Wait for any device to become available, or for all devices
* to fail.
*/
while ( sandev->active == NULL ) {
step();
if ( xfer_window ( &sandev->block ) != 0 ) {
sandev->block_rc = 0;
return 0;
if ( list_empty ( &sandev->opened ) ) {
/* Get status of the first device to be
* closed. Do this on the basis that earlier
* errors (e.g. "invalid IQN") are probably
* more interesting than later errors
* (e.g. "TCP timeout").
*/
rc = -ENODEV;
list_for_each_entry ( sanpath, &sandev->closed, list ) {
rc = sanpath->path_rc;
break;
}
DBGC ( sandev, "SAN %#02x never became available: %s\n",
sandev->drive, strerror ( rc ) );
goto err_none;
}
}
DBGC ( sandev, "SAN %#02x never became available: %s\n",
sandev->drive, strerror ( sandev->block_rc ) );
return sandev->block_rc;
}
/**
* Handle closure of underlying block device interface
*
* @v sandev SAN device
* @ret rc Reason for close
*/
static void sandev_block_close ( struct san_device *sandev, int rc ) {
/* Any closure is an error from our point of view */
if ( rc == 0 )
rc = -ENOTCONN;
DBGC ( sandev, "SAN %#02x went away: %s\n",
sandev->drive, strerror ( rc ) );
/* Close any outstanding command and restart interface */
sandev_restart ( sandev, rc );
}
/**
* Check SAN device flow control window
*
* @v sandev SAN device
*/
static size_t sandev_block_window ( struct san_device *sandev __unused ) {
/* We are never ready to receive data via this interface.
* This prevents objects that support both block and stream
* interfaces from attempting to send us stream data.
*/
assert ( ! list_empty ( &sandev->opened ) );
return 0;
err_none:
err_open:
sandev_restart ( sandev, rc );
return rc;
}
/** SAN device block interface operations */
static struct interface_operation sandev_block_op[] = {
INTF_OP ( intf_close, struct san_device *, sandev_block_close ),
INTF_OP ( xfer_window, struct san_device *, sandev_block_window ),
};
/** SAN device block interface descriptor */
static struct interface_descriptor sandev_block_desc =
INTF_DESC ( struct san_device, block, sandev_block_op );
/** SAN device read/write command parameters */
struct san_command_rw_params {
/** SAN device read/write operation */
@ -289,15 +410,19 @@ union san_command_params {
*/
static int sandev_command_rw ( struct san_device *sandev,
const union san_command_params *params ) {
struct san_path *sanpath = sandev->active;
size_t len = ( params->rw.count * sandev->capacity.blksize );
int rc;
/* Sanity check */
assert ( sanpath != NULL );
/* Initiate read/write command */
if ( ( rc = params->rw.block_rw ( &sandev->block, &sandev->command,
if ( ( rc = params->rw.block_rw ( &sanpath->block, &sandev->command,
params->rw.lba, params->rw.count,
params->rw.buffer, len ) ) != 0 ) {
DBGC ( sandev, "SAN %#02x could not initiate read/write: "
"%s\n", sandev->drive, strerror ( rc ) );
DBGC ( sandev, "SAN %#02x.%d could not initiate read/write: "
"%s\n", sandev->drive, sanpath->index, strerror ( rc ) );
return rc;
}
@ -314,13 +439,17 @@ static int sandev_command_rw ( struct san_device *sandev,
static int
sandev_command_read_capacity ( struct san_device *sandev,
const union san_command_params *params __unused){
struct san_path *sanpath = sandev->active;
int rc;
/* Sanity check */
assert ( sanpath != NULL );
/* Initiate read capacity command */
if ( ( rc = block_read_capacity ( &sandev->block,
if ( ( rc = block_read_capacity ( &sanpath->block,
&sandev->command ) ) != 0 ) {
DBGC ( sandev, "SAN %#02x could not initiate read capacity: "
"%s\n", sandev->drive, strerror ( rc ) );
DBGC ( sandev, "SAN %#02x.%d could not initiate read capacity: "
"%s\n", sandev->drive, sanpath->index, strerror ( rc ) );
return rc;
}
@ -526,22 +655,41 @@ static int sandev_parse_iso9660 ( struct san_device *sandev ) {
/**
* Allocate SAN device
*
* @v uris List of URIs
* @v count Number of URIs
* @v priv_size Size of private data
* @ret sandev SAN device, or NULL
*/
struct san_device * alloc_sandev ( struct uri *uri, size_t priv_size ) {
struct san_device * alloc_sandev ( struct uri **uris, unsigned int count,
size_t priv_size ) {
struct san_device *sandev;
struct san_path *sanpath;
size_t size;
unsigned int i;
/* Allocate and initialise structure */
sandev = zalloc ( sizeof ( *sandev ) + priv_size );
size = ( sizeof ( *sandev ) + ( count * sizeof ( sandev->path[0] ) ) );
sandev = zalloc ( size + priv_size );
if ( ! sandev )
return NULL;
ref_init ( &sandev->refcnt, sandev_free );
sandev->uri = uri_get ( uri );
intf_init ( &sandev->block, &sandev_block_desc, &sandev->refcnt );
sandev->block_rc = -EINPROGRESS;
intf_init ( &sandev->command, &sandev_command_desc, &sandev->refcnt );
timer_init ( &sandev->timer, sandev_command_expired, &sandev->refcnt );
sandev->priv = ( ( ( void * ) sandev ) + sizeof ( *sandev ) );
sandev->priv = ( ( ( void * ) sandev ) + size );
INIT_LIST_HEAD ( &sandev->opened );
INIT_LIST_HEAD ( &sandev->closed );
for ( i = 0 ; i < count ; i++ ) {
sanpath = &sandev->path[i];
sanpath->sandev = sandev;
sanpath->index = i;
sanpath->uri = uri_get ( uris[i] );
list_add_tail ( &sanpath->list, &sandev->closed );
intf_init ( &sanpath->block, &sanpath_block_desc,
&sandev->refcnt );
process_init_stopped ( &sanpath->process, &sanpath_process_desc,
&sandev->refcnt );
sanpath->path_rc = -EINPROGRESS;
}
return sandev;
}
@ -588,7 +736,7 @@ void unregister_sandev ( struct san_device *sandev ) {
assert ( ! timer_running ( &sandev->timer ) );
/* Shut down interfaces */
intfs_shutdown ( 0, &sandev->block, &sandev->command, NULL );
sandev_restart ( sandev, 0 );
/* Remove from list of SAN devices */
list_del ( &sandev->list );

View File

@ -71,12 +71,12 @@ static union {
/** "sanhook" command descriptor */
static struct command_descriptor sanhook_cmd =
COMMAND_DESC ( struct sanboot_options, opts.sanhook, 1, 1,
COMMAND_DESC ( struct sanboot_options, opts.sanhook, 1, MAX_ARGUMENTS,
"<root-path>" );
/** "sanboot" command descriptor */
static struct command_descriptor sanboot_cmd =
COMMAND_DESC ( struct sanboot_options, opts.sanboot, 0, 1,
COMMAND_DESC ( struct sanboot_options, opts.sanboot, 0, MAX_ARGUMENTS,
"[<root-path>]" );
/** "sanunhook" command descriptor */
@ -96,9 +96,10 @@ static int sanboot_core_exec ( int argc, char **argv,
struct command_descriptor *cmd,
int default_flags, int no_root_path_flags ) {
struct sanboot_options opts;
const char *root_path;
struct uri *uri;
struct uri *uris[argc];
int count;
int flags;
int i;
int rc;
/* Initialise options */
@ -109,17 +110,14 @@ static int sanboot_core_exec ( int argc, char **argv,
if ( ( rc = reparse_options ( argc, argv, cmd, &opts ) ) != 0 )
goto err_parse_options;
/* Parse root path, if present */
if ( argc > optind ) {
root_path = argv[optind];
uri = parse_uri ( root_path );
if ( ! uri ) {
/* Parse root paths, if present */
count = ( argc - optind );
for ( i = 0 ; i < count ; i++ ) {
uris[i] = parse_uri ( argv[ optind + i ] );
if ( ! uris[i] ) {
rc = -ENOMEM;
goto err_parse_uri;
}
} else {
root_path = NULL;
uri = NULL;
}
/* Construct flags */
@ -128,16 +126,18 @@ static int sanboot_core_exec ( int argc, char **argv,
flags |= URIBOOT_NO_SAN_DESCRIBE;
if ( opts.keep )
flags |= URIBOOT_NO_SAN_UNHOOK;
if ( ! root_path )
if ( ! count )
flags |= no_root_path_flags;
/* Boot from root path */
if ( ( rc = uriboot ( NULL, uri, opts.drive, flags ) ) != 0 )
if ( ( rc = uriboot ( NULL, uris, count, opts.drive, flags ) ) != 0 )
goto err_uriboot;
err_uriboot:
uri_put ( uri );
i = count;
err_parse_uri:
for ( i-- ; i >= 0 ; i-- )
uri_put ( uris[i] );
err_parse_options:
return rc;
}

View File

@ -16,9 +16,29 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/list.h>
#include <ipxe/uri.h>
#include <ipxe/retry.h>
#include <ipxe/process.h>
#include <ipxe/blockdev.h>
#include <config/sanboot.h>
/** A SAN path */
struct san_path {
/** Containing SAN device */
struct san_device *sandev;
/** Path index */
unsigned int index;
/** SAN device URI */
struct uri *uri;
/** List of open/closed paths */
struct list_head list;
/** Underlying block device interface */
struct interface block;
/** Process */
struct process process;
/** Path status */
int path_rc;
};
/** A SAN device */
struct san_device {
/** Reference count */
@ -26,16 +46,9 @@ struct san_device {
/** List of SAN devices */
struct list_head list;
/** SAN device URI */
struct uri *uri;
/** Drive number */
unsigned int drive;
/** Underlying block device interface */
struct interface block;
/** Current device status */
int block_rc;
/** Command interface */
struct interface command;
/** Command timeout timer */
@ -57,6 +70,15 @@ struct san_device {
/** Driver private data */
void *priv;
/** Current active path */
struct san_path *active;
/** List of opened SAN paths */
struct list_head opened;
/** List of closed SAN paths */
struct list_head closed;
/** SAN paths */
struct san_path path[0];
};
/**
@ -99,11 +121,12 @@ struct san_device {
/**
* Hook SAN device
*
* @v uri URI
* @v drive Drive number
* @v uris List of URIs
* @v count Number of URIs
* @ret drive Drive number, or negative error
*/
int san_hook ( struct uri *uri, unsigned int drive );
int san_hook ( unsigned int drive, struct uri **uris, unsigned int count );
/**
* Unhook SAN device
@ -191,7 +214,7 @@ static inline uint64_t sandev_capacity ( struct san_device *sandev ) {
* @ret needs_reopen SAN device needs to be reopened
*/
static inline int sandev_needs_reopen ( struct san_device *sandev ) {
return ( sandev->block_rc != 0 );
return ( sandev->active == NULL );
}
extern struct san_device * sandev_find ( unsigned int drive );
@ -203,7 +226,8 @@ extern int sandev_rw ( struct san_device *sandev, uint64_t lba,
struct interface *data,
uint64_t lba, unsigned int count,
userptr_t buffer, size_t len ) );
extern struct san_device * alloc_sandev ( struct uri *uri, size_t priv_size );
extern struct san_device * alloc_sandev ( struct uri **uris, unsigned int count,
size_t priv_size );
extern int register_sandev ( struct san_device *sandev );
extern void unregister_sandev ( struct san_device *sandev );
extern unsigned int san_default_drive ( void );

View File

@ -30,7 +30,8 @@ extern void set_autoboot_busloc ( unsigned int bus_type,
unsigned int location );
extern void set_autoboot_ll_addr ( const void *ll_addr, size_t len );
extern int uriboot ( struct uri *filename, struct uri *root_path, int drive,
extern int uriboot ( struct uri *filename, struct uri **root_paths,
unsigned int root_path_count, int drive,
unsigned int flags );
extern struct uri *
fetch_next_server_and_filename ( struct settings *settings );

View File

@ -251,11 +251,13 @@ static void efi_block_connect ( struct san_device *sandev ) {
/**
* Hook EFI block device
*
* @v uri URI
* @v drive Drive number
* @v uris List of URIs
* @v count Number of URIs
* @ret drive Drive number, or negative error
*/
static int efi_block_hook ( struct uri *uri, unsigned int drive ) {
static int efi_block_hook ( unsigned int drive, struct uri **uris,
unsigned int count ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
EFI_DEVICE_PATH_PROTOCOL *end;
struct efi_block_vendor_path *vendor;
@ -270,6 +272,13 @@ static int efi_block_hook ( struct uri *uri, unsigned int drive ) {
EFI_STATUS efirc;
int rc;
/* Sanity check */
if ( ! count ) {
DBG ( "EFIBLK has no URIs\n" );
rc = -ENOTTY;
goto err_no_uris;
}
/* Find an appropriate parent device handle */
snpdev = last_opened_snpdev();
if ( ! snpdev ) {
@ -280,14 +289,14 @@ static int efi_block_hook ( struct uri *uri, unsigned int drive ) {
/* Calculate length of private data */
prefix_len = efi_devpath_len ( snpdev->path );
uri_len = format_uri ( uri, NULL, 0 );
uri_len = format_uri ( uris[0], NULL, 0 );
vendor_len = ( sizeof ( *vendor ) +
( ( uri_len + 1 /* NUL */ ) * sizeof ( wchar_t ) ) );
len = ( sizeof ( *block ) + uri_len + 1 /* NUL */ + prefix_len +
vendor_len + sizeof ( *end ) );
/* Allocate and initialise structure */
sandev = alloc_sandev ( uri, len );
sandev = alloc_sandev ( uris, count, len );
if ( ! sandev ) {
rc = -ENOMEM;
goto err_alloc;
@ -315,7 +324,7 @@ static int efi_block_hook ( struct uri *uri, unsigned int drive ) {
vendor->vendor.Header.Length[1] = ( vendor_len >> 8 );
memcpy ( &vendor->vendor.Guid, &ipxe_block_device_path_guid,
sizeof ( vendor->vendor.Guid ) );
format_uri ( uri, uri_buf, ( uri_len + 1 /* NUL */ ) );
format_uri ( uris[0], uri_buf, ( uri_len + 1 /* NUL */ ) );
efi_snprintf ( vendor->uri, ( uri_len + 1 /* NUL */ ), "%s", uri_buf );
end = ( ( ( void * ) vendor ) + vendor_len );
end->Type = END_DEVICE_PATH_TYPE;
@ -364,6 +373,7 @@ static int efi_block_hook ( struct uri *uri, unsigned int drive ) {
sandev_put ( sandev );
err_alloc:
err_no_snpdev:
err_no_uris:
return rc;
}
@ -413,6 +423,7 @@ static int efi_block_describe ( unsigned int drive ) {
} xbftab;
static UINTN key;
struct san_device *sandev;
struct san_path *sanpath;
size_t len;
EFI_STATUS efirc;
int rc;
@ -446,6 +457,8 @@ static int efi_block_describe ( unsigned int drive ) {
if ( sandev_needs_reopen ( sandev ) &&
( ( rc = sandev_reopen ( sandev ) ) != 0 ) )
return rc;
sanpath = sandev->active;
assert ( sanpath != NULL );
/* Clear table */
memset ( &xbftab, 0, sizeof ( xbftab ) );
@ -457,7 +470,7 @@ static int efi_block_describe ( unsigned int drive ) {
sizeof ( xbftab.acpi.oem_table_id ) );
/* Fill in remaining parameters */
if ( ( rc = acpi_describe ( &sandev->block, &xbftab.acpi,
if ( ( rc = acpi_describe ( &sanpath->block, &xbftab.acpi,
sizeof ( xbftab ) ) ) != 0 ) {
DBGC ( sandev, "EFIBLK %#02x could not create ACPI "
"description: %s\n", sandev->drive, strerror ( rc ) );

View File

@ -109,7 +109,8 @@ const struct setting skip_san_boot_setting __setting ( SETTING_SANBOOT_EXTRA,
* Boot from filename and root-path URIs
*
* @v filename Filename
* @v root_path Root path
* @v root_paths Root path(s)
* @v root_path_count Number of root paths
* @v drive SAN drive (if applicable)
* @v flags Boot action flags
* @ret rc Return status code
@ -120,14 +121,14 @@ const struct setting skip_san_boot_setting __setting ( SETTING_SANBOOT_EXTRA,
* provide backwards compatibility for the "keep-san" and
* "skip-san-boot" options.
*/
int uriboot ( struct uri *filename, struct uri *root_path, int drive,
unsigned int flags ) {
int uriboot ( struct uri *filename, struct uri **root_paths,
unsigned int root_path_count, int drive, unsigned int flags ) {
struct image *image;
int rc;
/* Hook SAN device, if applicable */
if ( root_path ) {
drive = san_hook ( root_path, drive );
if ( root_path_count ) {
drive = san_hook ( drive, root_paths, root_path_count );
if ( drive < 0 ) {
rc = drive;
printf ( "Could not open SAN device: %s\n",
@ -396,7 +397,8 @@ int netboot ( struct net_device *netdev ) {
}
/* Boot using next server, filename and root path */
if ( ( rc = uriboot ( filename, root_path, san_default_drive(),
if ( ( rc = uriboot ( filename, &root_path, ( root_path ? 1 : 0 ),
san_default_drive(),
( root_path ? 0 : URIBOOT_NO_SAN ) ) ) != 0 )
goto err_uriboot;

View File

@ -378,7 +378,7 @@ int pxe_menu_boot ( struct net_device *netdev ) {
return -ENOMEM;
/* Attempt boot */
rc = uriboot ( uri, NULL, 0, URIBOOT_NO_SAN );
rc = uriboot ( uri, NULL, 0, 0, URIBOOT_NO_SAN );
uri_put ( uri );
return rc;
}