summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/arch/x86/interface/pcbios/int13.c20
-rw-r--r--src/core/dummy_sanboot.c8
-rw-r--r--src/core/null_sanboot.c5
-rw-r--r--src/core/sanboot.c294
-rw-r--r--src/hci/commands/sanboot_cmd.c30
-rw-r--r--src/include/ipxe/sanboot.h46
-rw-r--r--src/include/usr/autoboot.h3
-rw-r--r--src/interface/efi/efi_block.c25
-rw-r--r--src/usr/autoboot.c14
-rw-r--r--src/usr/pxemenu.c2
10 files changed, 323 insertions, 124 deletions
diff --git a/src/arch/x86/interface/pcbios/int13.c b/src/arch/x86/interface/pcbios/int13.c
index 23cfefca..c322440e 100644
--- a/src/arch/x86/interface/pcbios/int13.c
+++ b/src/arch/x86/interface/pcbios/int13.c
@@ -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 ) );
diff --git a/src/core/dummy_sanboot.c b/src/core/dummy_sanboot.c
index 16347747..64d5206f 100644
--- a/src/core/dummy_sanboot.c
+++ b/src/core/dummy_sanboot.c
@@ -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;
diff --git a/src/core/null_sanboot.c b/src/core/null_sanboot.c
index 31a8a56b..42fb0682 100644
--- a/src/core/null_sanboot.c
+++ b/src/core/null_sanboot.c
@@ -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;
}
diff --git a/src/core/sanboot.c b/src/core/sanboot.c
index 88d254ff..90bf763b 100644
--- a/src/core/sanboot.c
+++ b/src/core/sanboot.c
@@ -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 );
}
@@ -163,85 +167,92 @@ static void sandev_command_expired ( struct retry_timer *timer,
}
/**
- * Restart SAN device interface
+ * Open SAN path
*
- * @v sandev SAN device
- * @v rc Reason for restart
+ * @v sanpath SAN path
+ * @ret rc Return status code
*/
-static void sandev_restart ( struct san_device *sandev, int rc ) {
+static int sanpath_open ( struct san_path *sanpath ) {
+ struct san_device *sandev = sanpath->sandev;
+ int rc;
- /* Restart block device interface */
- intfs_restart ( rc, &sandev->command, &sandev->block, NULL );
+ /* Sanity check */
+ list_check_contains_entry ( sanpath, &sandev->closed, list );
- /* Close any outstanding command */
- sandev_command_close ( sandev, rc );
+ /* 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 );
- /* Record device error */
- sandev->block_rc = rc;
+ /* Mark as opened */
+ list_del ( &sanpath->list );
+ list_add_tail ( &sanpath->list, &sandev->opened );
+
+ /* Record as in progress */
+ sanpath->path_rc = -EINPROGRESS;
+
+ return 0;
}
/**
- * (Re)open SAN device
+ * Close SAN path
*
- * @v sandev SAN device
- * @ret rc Return status code
- *
- * This function will block until the device is available.
+ * @v sanpath SAN path
+ * @v rc Reason for close
*/
-int sandev_reopen ( struct san_device *sandev ) {
- int rc;
-
- /* Close any outstanding command and restart interface */
- sandev_restart ( sandev, -ECONNRESET );
-
- /* 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;
+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 );
}
-
- /* Wait for device to become available */
- while ( sandev->block_rc == -EINPROGRESS ) {
- step();
- if ( xfer_window ( &sandev->block ) != 0 ) {
- sandev->block_rc = 0;
- return 0;
- }
- }
-
- 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
+ * @v sanpath SAN path
+ * @v rc Reason for close
*/
-static void sandev_block_close ( struct san_device *sandev, int rc ) {
+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 went away: %s\n",
- sandev->drive, strerror ( rc ) );
+ DBGC ( sandev, "SAN %#02x.%d closed: %s\n",
+ sandev->drive, sanpath->index, strerror ( rc ) );
- /* Close any outstanding command and restart interface */
- sandev_restart ( sandev, rc );
+ /* Close path */
+ sanpath_close ( sanpath, rc );
}
/**
- * Check SAN device flow control window
+ * Check flow control window
*
- * @v sandev SAN device
+ * @v sanpath SAN path
*/
-static size_t sandev_block_window ( struct san_device *sandev __unused ) {
+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
@@ -250,15 +261,125 @@ static size_t sandev_block_window ( struct san_device *sandev __unused ) {
return 0;
}
-/** 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 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 device block interface descriptor */
-static struct interface_descriptor sandev_block_desc =
- INTF_DESC ( struct san_device, block, sandev_block_op );
+/** 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
+ *
+ * @v sandev SAN device
+ * @v rc Reason for restart
+ */
+static void sandev_restart ( struct san_device *sandev, int rc ) {
+ struct san_path *sanpath;
+
+ /* 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 );
+}
+
+/**
+ * (Re)open SAN device
+ *
+ * @v sandev SAN device
+ * @ret rc Return status code
+ *
+ * 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 interfaces */
+ sandev_restart ( sandev, -ECONNRESET );
+ assert ( sandev->active == NULL );
+ assert ( list_empty ( &sandev->opened ) );
+
+ /* 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 any device to become available, or for all devices
+ * to fail.
+ */
+ while ( sandev->active == NULL ) {
+ step();
+ 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;
+ }
+ }
+
+ assert ( ! list_empty ( &sandev->opened ) );
+ return 0;
+
+ err_none:
+ err_open:
+ sandev_restart ( sandev, rc );
+ return rc;
+}
/** SAN device read/write command parameters */
struct san_command_rw_params {
@@ -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 );
diff --git a/src/hci/commands/sanboot_cmd.c b/src/hci/commands/sanboot_cmd.c
index 24ec8bc4..9965ec15 100644
--- a/src/hci/commands/sanboot_cmd.c
+++ b/src/hci/commands/sanboot_cmd.c
@@ -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;
}
diff --git a/src/include/ipxe/sanboot.h b/src/include/ipxe/sanboot.h
index c2e57f71..a8b0291d 100644
--- a/src/include/ipxe/sanboot.h
+++ b/src/include/ipxe/sanboot.h
@@ -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 );
diff --git a/src/include/usr/autoboot.h b/src/include/usr/autoboot.h
index 4db226b9..c62d06c6 100644
--- a/src/include/usr/autoboot.h
+++ b/src/include/usr/autoboot.h
@@ -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 );
diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c
index 10504f6a..9679fc0d 100644
--- a/src/interface/efi/efi_block.c
+++ b/src/interface/efi/efi_block.c
@@ -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 ) );
diff --git a/src/usr/autoboot.c b/src/usr/autoboot.c
index 57bf96ef..a0c79351 100644
--- a/src/usr/autoboot.c
+++ b/src/usr/autoboot.c
@@ -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;
diff --git a/src/usr/pxemenu.c b/src/usr/pxemenu.c
index 2d05d3f5..391d698a 100644
--- a/src/usr/pxemenu.c
+++ b/src/usr/pxemenu.c
@@ -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;
}