diff options
author | Michael Brown | 2017-03-26 14:12:11 +0200 |
---|---|---|
committer | Michael Brown | 2017-03-26 15:06:02 +0200 |
commit | bb5a54b79a414082d0b39d478a8b3332c56d68e5 (patch) | |
tree | c022d5b8ed56be56414eb007273aeacd57c44d37 /src/interface/efi | |
parent | [block] Add dummy SAN device (diff) | |
download | ipxe-bb5a54b79a414082d0b39d478a8b3332c56d68e5.tar.gz ipxe-bb5a54b79a414082d0b39d478a8b3332c56d68e5.tar.xz ipxe-bb5a54b79a414082d0b39d478a8b3332c56d68e5.zip |
[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>
Diffstat (limited to 'src/interface/efi')
-rw-r--r-- | src/interface/efi/efi_block.c | 25 |
1 files changed, 19 insertions, 6 deletions
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 ) ); |