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 #include -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 ); } @@ -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 ); 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, "" ); /** "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, "[]" ); /** "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 #include #include +#include #include #include +/** 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; }