summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/arch/x86/interface/pcbios/int13.c117
-rw-r--r--src/core/acpi.c85
-rw-r--r--src/core/dummy_sanboot.c25
-rw-r--r--src/core/null_sanboot.c5
-rw-r--r--src/core/sanboot.c101
-rw-r--r--src/drivers/block/ibft.c392
-rw-r--r--src/drivers/block/srp.c68
-rw-r--r--src/include/ipxe/acpi.h91
-rw-r--r--src/include/ipxe/aoe.h2
-rw-r--r--src/include/ipxe/ibft.h36
-rw-r--r--src/include/ipxe/iscsi.h7
-rw-r--r--src/include/ipxe/sanboot.h24
-rw-r--r--src/include/ipxe/srp.h2
-rw-r--r--src/interface/efi/efi_block.c148
-rw-r--r--src/net/aoe.c90
-rw-r--r--src/net/fcp.c20
-rw-r--r--src/net/infiniband/ib_srp.c141
-rw-r--r--src/net/tcp/httpblock.c18
-rw-r--r--src/net/tcp/httpcore.c17
-rw-r--r--src/net/tcp/iscsi.c14
-rw-r--r--src/usr/autoboot.c10
21 files changed, 926 insertions, 487 deletions
diff --git a/src/arch/x86/interface/pcbios/int13.c b/src/arch/x86/interface/pcbios/int13.c
index 0bc123d7..b793d730 100644
--- a/src/arch/x86/interface/pcbios/int13.c
+++ b/src/arch/x86/interface/pcbios/int13.c
@@ -1239,13 +1239,14 @@ static void int13_unhook_vector ( void ) {
* @v drive Drive number
* @v uris List of URIs
* @v count Number of URIs
+ * @v flags Flags
* @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 ( unsigned int drive, struct uri **uris,
- unsigned int count ) {
+ unsigned int count, unsigned int flags ) {
struct san_device *sandev;
struct int13_data *int13;
unsigned int natural_drive;
@@ -1267,14 +1268,13 @@ static int int13_hook ( unsigned int drive, struct uri **uris,
rc = -ENOMEM;
goto err_alloc;
}
- sandev->drive = drive;
int13 = sandev->priv;
int13->natural_drive = natural_drive;
/* Register SAN device */
- if ( ( rc = register_sandev ( sandev ) ) != 0 ) {
+ if ( ( rc = register_sandev ( sandev, drive, flags ) ) != 0 ) {
DBGC ( sandev, "INT13 drive %02x could not register: %s\n",
- sandev->drive, strerror ( rc ) );
+ drive, strerror ( rc ) );
goto err_register;
}
@@ -1544,70 +1544,83 @@ static int int13_boot ( unsigned int drive ) {
return -ECANCELED; /* -EIMPOSSIBLE */
}
-/** A boot firmware table generated by iPXE */
-union xbft_table {
- /** ACPI header */
- struct acpi_description_header acpi;
- /** Padding */
- char pad[768];
-};
+/** Maximum size of boot firmware table(s) */
+#define XBFTAB_SIZE 768
+
+/** Alignment of boot firmware table entries */
+#define XBFTAB_ALIGN 16
-/** The boot firmware table generated by iPXE */
-static union xbft_table __bss16 ( xbftab ) __attribute__ (( aligned ( 16 ) ));
+/** The boot firmware table(s) generated by iPXE */
+static uint8_t __bss16_array ( xbftab, [XBFTAB_SIZE] )
+ __attribute__ (( aligned ( XBFTAB_ALIGN ) ));
#define xbftab __use_data16 ( xbftab )
+/** Total used length of boot firmware tables */
+static size_t xbftab_used;
+
/**
- * Describe SAN device for SAN-booted operating system
+ * Install ACPI table
*
- * @v drive Drive number
+ * @v acpi ACPI description header
* @ret rc Return status code
*/
-static int int13_describe ( unsigned int drive ) {
- struct san_device *sandev;
- struct san_path *sanpath;
+static int int13_install ( struct acpi_header *acpi ) {
struct segoff xbft_address;
- int rc;
-
- /* Find drive */
- sandev = sandev_find ( drive );
- if ( ! sandev ) {
- DBG ( "INT13 cannot find drive %02x\n", drive );
- return -ENODEV;
+ struct acpi_header *installed;
+ size_t len;
+
+ /* Check length */
+ len = acpi->length;
+ if ( len > ( sizeof ( xbftab ) - xbftab_used ) ) {
+ DBGC ( acpi, "INT13 out of space for %s table\n",
+ acpi_name ( acpi->signature ) );
+ return -ENOSPC;
}
- /* Reopen block device if necessary */
- if ( sandev_needs_reopen ( sandev ) &&
- ( ( rc = sandev_reopen ( sandev ) ) != 0 ) )
- return rc;
- sanpath = sandev->active;
- assert ( sanpath != NULL );
+ /* Install table */
+ installed = ( ( ( void * ) xbftab ) + xbftab_used );
+ memcpy ( installed, acpi, len );
+ xbft_address.segment = rm_ds;
+ xbft_address.offset = __from_data16 ( installed );
+
+ /* Fill in common parameters */
+ strncpy ( installed->oem_id, "FENSYS",
+ sizeof ( installed->oem_id ) );
+ strncpy ( installed->oem_table_id, "iPXE",
+ sizeof ( installed->oem_table_id ) );
+
+ /* Fix checksum */
+ acpi_fix_checksum ( installed );
+
+ /* Update used length */
+ xbftab_used = ( ( xbftab_used + len + XBFTAB_ALIGN - 1 ) &
+ ~( XBFTAB_ALIGN - 1 ) );
+
+ DBGC ( acpi, "INT13 installed %s:\n",
+ acpi_name ( installed->signature ) );
+ DBGC_HDA ( acpi, xbft_address, installed, len );
+ return 0;
+}
- /* Clear table */
+/**
+ * Describe SAN devices for SAN-booted operating system
+ *
+ * @ret rc Return status code
+ */
+static int int13_describe ( void ) {
+ int rc;
+
+ /* Clear tables */
memset ( &xbftab, 0, sizeof ( xbftab ) );
+ xbftab_used = 0;
- /* Fill in common parameters */
- strncpy ( xbftab.acpi.oem_id, "FENSYS",
- sizeof ( xbftab.acpi.oem_id ) );
- strncpy ( xbftab.acpi.oem_table_id, "iPXE",
- sizeof ( xbftab.acpi.oem_table_id ) );
-
- /* Fill in remaining parameters */
- 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 ) );
+ /* Install ACPI tables */
+ if ( ( rc = acpi_install ( int13_install ) ) != 0 ) {
+ DBG ( "INT13 could not install ACPI tables: %s\n",
+ strerror ( rc ) );
return rc;
}
- /* Fix up ACPI checksum */
- acpi_fix_checksum ( &xbftab.acpi );
- xbft_address.segment = rm_ds;
- xbft_address.offset = __from_data16 ( &xbftab );
- DBGC ( sandev, "INT13 drive %02x described using boot firmware "
- "table:\n", sandev->drive );
- DBGC_HDA ( sandev, xbft_address, &xbftab,
- le32_to_cpu ( xbftab.acpi.length ) );
-
return 0;
}
diff --git a/src/core/acpi.c b/src/core/acpi.c
index 955637e0..8ebe4b19 100644
--- a/src/core/acpi.c
+++ b/src/core/acpi.c
@@ -43,27 +43,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
/**
- * Transcribe ACPI table signature (for debugging)
- *
- * @v signature ACPI table signature
- * @ret name ACPI table signature name
- */
-static const char * acpi_name ( uint32_t signature ) {
- static union {
- uint32_t signature;
- char name[5];
- } u;
-
- u.signature = cpu_to_le32 ( signature );
- return u.name;
-}
-
-/**
* Fix up ACPI table checksum
*
* @v acpi ACPI table header
*/
-void acpi_fix_checksum ( struct acpi_description_header *acpi ) {
+void acpi_fix_checksum ( struct acpi_header *acpi ) {
unsigned int i = 0;
uint8_t sum = 0;
@@ -147,7 +131,7 @@ userptr_t acpi_find_rsdt ( userptr_t ebda ) {
* @ret table Table, or UNULL if not found
*/
userptr_t acpi_find ( userptr_t rsdt, uint32_t signature, unsigned int index ) {
- struct acpi_description_header acpi;
+ struct acpi_header acpi;
struct acpi_rsdt *rsdtab;
typeof ( rsdtab->entry[0] ) entry;
userptr_t table;
@@ -227,7 +211,7 @@ userptr_t acpi_find ( userptr_t rsdt, uint32_t signature, unsigned int index ) {
* the ACPI specification itself.
*/
static int acpi_sx_zsdt ( userptr_t zsdt, uint32_t signature ) {
- struct acpi_description_header acpi;
+ struct acpi_header acpi;
union {
uint32_t dword;
uint8_t byte[4];
@@ -331,34 +315,73 @@ int acpi_sx ( userptr_t rsdt, uint32_t signature ) {
/******************************************************************************
*
- * Interface methods
+ * Descriptors
*
******************************************************************************
*/
/**
- * Describe object in an ACPI table
+ * Add ACPI descriptor
+ *
+ * @v desc ACPI descriptor
+ */
+void acpi_add ( struct acpi_descriptor *desc ) {
+
+ /* Add to list of descriptors */
+ ref_get ( desc->refcnt );
+ list_add_tail ( &desc->list, &desc->model->descs );
+}
+
+/**
+ * Remove ACPI descriptor
+ *
+ * @v desc ACPI descriptor
+ */
+void acpi_del ( struct acpi_descriptor *desc ) {
+
+ /* Remove from list of descriptors */
+ list_check_contains_entry ( desc, &desc->model->descs, list );
+ list_del ( &desc->list );
+ ref_put ( desc->refcnt );
+}
+
+/**
+ * Get object's ACPI descriptor
*
* @v intf Interface
- * @v acpi ACPI table
- * @v len Length of ACPI table
- * @ret rc Return status code
+ * @ret desc ACPI descriptor, or NULL
*/
-int acpi_describe ( struct interface *intf,
- struct acpi_description_header *acpi, size_t len ) {
+struct acpi_descriptor * acpi_describe ( struct interface *intf ) {
struct interface *dest;
acpi_describe_TYPE ( void * ) *op =
intf_get_dest_op ( intf, acpi_describe, &dest );
void *object = intf_object ( dest );
- int rc;
+ struct acpi_descriptor *desc;
if ( op ) {
- rc = op ( object, acpi, len );
+ desc = op ( object );
} else {
- /* Default is to fail to describe */
- rc = -EOPNOTSUPP;
+ desc = NULL;
}
intf_put ( dest );
- return rc;
+ return desc;
+}
+
+/**
+ * Install ACPI tables
+ *
+ * @v install Table installation method
+ * @ret rc Return status code
+ */
+int acpi_install ( int ( * install ) ( struct acpi_header *acpi ) ){
+ struct acpi_model *model;
+ int rc;
+
+ for_each_table_entry ( model, ACPI_MODELS ) {
+ if ( ( rc = model->install ( install ) ) != 0 )
+ return rc;
+ }
+
+ return 0;
}
diff --git a/src/core/dummy_sanboot.c b/src/core/dummy_sanboot.c
index 64d5206f..08180852 100644
--- a/src/core/dummy_sanboot.c
+++ b/src/core/dummy_sanboot.c
@@ -38,10 +38,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* @v drive Drive number
* @v uris List of URIs
* @v count Number of URIs
+ * @v flags Flags
* @ret drive Drive number, or negative error
*/
static int dummy_san_hook ( unsigned int drive, struct uri **uris,
- unsigned int count ) {
+ unsigned int count, unsigned int flags ) {
struct san_device *sandev;
int rc;
@@ -51,10 +52,9 @@ static int dummy_san_hook ( unsigned int drive, struct uri **uris,
rc = -ENOMEM;
goto err_alloc;
}
- sandev->drive = drive;
/* Register SAN device */
- if ( ( rc = register_sandev ( sandev ) ) != 0 ) {
+ if ( ( rc = register_sandev ( sandev, drive, flags ) ) != 0 ) {
DBGC ( sandev, "SAN %#02x could not register: %s\n",
sandev->drive, strerror ( rc ) );
goto err_register;
@@ -102,15 +102,28 @@ static int dummy_san_boot ( unsigned int drive __unused ) {
}
/**
- * Describe dummy SAN device
+ * Install ACPI table
*
- * @v drive Drive number
+ * @v acpi ACPI description header
+ * @ret rc Return status code
*/
-static int dummy_san_describe ( unsigned int drive __unused ) {
+static int dummy_install ( struct acpi_header *acpi ) {
+ DBGC ( acpi, "ACPI table %s:\n", acpi_name ( acpi->signature ) );
+ DBGC_HDA ( acpi, 0, acpi, le32_to_cpu ( acpi->length ) );
return 0;
}
+/**
+ * Describe dummy SAN device
+ *
+ * @ret rc Return status code
+ */
+static int dummy_san_describe ( void ) {
+
+ return acpi_install ( dummy_install );
+}
+
PROVIDE_SANBOOT ( dummy, san_hook, dummy_san_hook );
PROVIDE_SANBOOT ( dummy, san_unhook, dummy_san_unhook );
PROVIDE_SANBOOT ( dummy, san_boot, dummy_san_boot );
diff --git a/src/core/null_sanboot.c b/src/core/null_sanboot.c
index 42fb0682..b09562e2 100644
--- a/src/core/null_sanboot.c
+++ b/src/core/null_sanboot.c
@@ -28,7 +28,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
static int null_san_hook ( unsigned int drive __unused,
struct uri **uris __unused,
- unsigned int count __unused ) {
+ unsigned int count __unused,
+ unsigned int flags __unused ) {
return -EOPNOTSUPP;
}
@@ -40,7 +41,7 @@ static int null_san_boot ( unsigned int drive __unused ) {
return -EOPNOTSUPP;
}
-static int null_san_describe ( unsigned int drive __unused ) {
+static int null_san_describe ( void ) {
return -EOPNOTSUPP;
}
diff --git a/src/core/sanboot.c b/src/core/sanboot.c
index 03beae79..f134f76a 100644
--- a/src/core/sanboot.c
+++ b/src/core/sanboot.c
@@ -119,8 +119,10 @@ static void sandev_free ( struct refcnt *refcnt ) {
assert ( ! timer_running ( &sandev->timer ) );
assert ( ! sandev->active );
assert ( list_empty ( &sandev->opened ) );
- for ( i = 0 ; i < sandev->paths ; i++ )
+ for ( i = 0 ; i < sandev->paths ; i++ ) {
uri_put ( sandev->path[i].uri );
+ assert ( sandev->path[i].desc == NULL );
+ }
free ( sandev );
}
@@ -199,6 +201,15 @@ static int sanpath_open ( struct san_path *sanpath ) {
return rc;
}
+ /* Update ACPI descriptor, if applicable */
+ if ( ! ( sandev->flags & SAN_NO_DESCRIBE ) ) {
+ if ( sanpath->desc )
+ acpi_del ( sanpath->desc );
+ sanpath->desc = acpi_describe ( &sanpath->block );
+ if ( sanpath->desc )
+ acpi_add ( sanpath->desc );
+ }
+
/* Start process */
process_add ( &sanpath->process );
@@ -607,6 +618,72 @@ int sandev_rw ( struct san_device *sandev, uint64_t lba,
}
/**
+ * Describe SAN device
+ *
+ * @v sandev SAN device
+ * @ret rc Return status code
+ *
+ * Allow connections to progress until all existent path descriptors
+ * are complete.
+ */
+static int sandev_describe ( struct san_device *sandev ) {
+ struct san_path *sanpath;
+ struct acpi_descriptor *desc;
+ int rc;
+
+ /* Wait for all paths to be either described or closed */
+ while ( 1 ) {
+
+ /* Allow connections to progress */
+ step();
+
+ /* Fail if any closed path has an incomplete descriptor */
+ list_for_each_entry ( sanpath, &sandev->closed, list ) {
+ desc = sanpath->desc;
+ if ( ! desc )
+ continue;
+ if ( ( rc = desc->model->complete ( desc ) ) != 0 ) {
+ DBGC ( sandev, "SAN %#02x.%d could not be "
+ "described: %s\n", sandev->drive,
+ sanpath->index, strerror ( rc ) );
+ return rc;
+ }
+ }
+
+ /* Succeed if no paths have an incomplete descriptor */
+ rc = 0;
+ list_for_each_entry ( sanpath, &sandev->opened, list ) {
+ desc = sanpath->desc;
+ if ( ! desc )
+ continue;
+ if ( ( rc = desc->model->complete ( desc ) ) != 0 )
+ break;
+ }
+ if ( rc == 0 )
+ return 0;
+ }
+}
+
+/**
+ * Remove SAN device descriptors
+ *
+ * @v sandev SAN device
+ */
+static void sandev_undescribe ( struct san_device *sandev ) {
+ struct san_path *sanpath;
+ unsigned int i;
+
+ /* Remove all ACPI descriptors */
+ for ( i = 0 ; i < sandev->paths ; i++ ) {
+ sanpath = &sandev->path[i];
+ if ( sanpath->desc ) {
+ acpi_del ( sanpath->desc );
+ sanpath->desc = NULL;
+ }
+ }
+}
+
+/**
* Configure SAN device as a CD-ROM, if applicable
*
* @v sandev SAN device
@@ -729,18 +806,25 @@ struct san_device * alloc_sandev ( struct uri **uris, unsigned int count,
* Register SAN device
*
* @v sandev SAN device
+ * @v drive Drive number
+ * @v flags Flags
* @ret rc Return status code
*/
-int register_sandev ( struct san_device *sandev ) {
+int register_sandev ( struct san_device *sandev, unsigned int drive,
+ unsigned int flags ) {
int rc;
/* Check that drive number is not in use */
- if ( sandev_find ( sandev->drive ) != NULL ) {
- DBGC ( sandev, "SAN %#02x is already in use\n", sandev->drive );
+ if ( sandev_find ( drive ) != NULL ) {
+ DBGC ( sandev, "SAN %#02x is already in use\n", drive );
rc = -EADDRINUSE;
goto err_in_use;
}
+ /* Record drive number and flags */
+ sandev->drive = drive;
+ sandev->flags = flags;
+
/* Check that device is capable of being opened (i.e. that all
* URIs are well-formed and that at least one path is
* working).
@@ -748,6 +832,10 @@ int register_sandev ( struct san_device *sandev ) {
if ( ( rc = sandev_reopen ( sandev ) ) != 0 )
goto err_reopen;
+ /* Describe device */
+ if ( ( rc = sandev_describe ( sandev ) ) != 0 )
+ goto err_describe;
+
/* Read device capacity */
if ( ( rc = sandev_command ( sandev, sandev_command_read_capacity,
NULL ) ) != 0 )
@@ -766,8 +854,10 @@ int register_sandev ( struct san_device *sandev ) {
list_del ( &sandev->list );
err_iso9660:
err_capacity:
+ err_describe:
err_reopen:
sandev_restart ( sandev, rc );
+ sandev_undescribe ( sandev );
err_in_use:
return rc;
}
@@ -788,6 +878,9 @@ void unregister_sandev ( struct san_device *sandev ) {
/* Shut down interfaces */
sandev_restart ( sandev, 0 );
+ /* Remove ACPI descriptors */
+ sandev_undescribe ( sandev );
+
DBGC ( sandev, "SAN %#02x unregistered\n", sandev->drive );
}
diff --git a/src/drivers/block/ibft.c b/src/drivers/block/ibft.c
index 91a808d8..a9d21f9a 100644
--- a/src/drivers/block/ibft.c
+++ b/src/drivers/block/ibft.c
@@ -28,6 +28,7 @@
FILE_LICENCE ( BSD2 );
#include <stdint.h>
+#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
@@ -38,6 +39,7 @@ FILE_LICENCE ( BSD2 );
#include <ipxe/netdevice.h>
#include <ipxe/ethernet.h>
#include <ipxe/vlan.h>
+#include <ipxe/tcpip.h>
#include <ipxe/dhcp.h>
#include <ipxe/iscsi.h>
#include <ipxe/ibft.h>
@@ -54,38 +56,32 @@ FILE_LICENCE ( BSD2 );
*/
/**
- * An iBFT created by iPXE
- *
- */
-struct ipxe_ibft {
- /** The fixed section */
- struct ibft_table table;
- /** The Initiator section */
- struct ibft_initiator initiator __attribute__ (( aligned ( 16 ) ));
- /** The NIC section */
- struct ibft_nic nic __attribute__ (( aligned ( 16 ) ));
- /** The Target section */
- struct ibft_target target __attribute__ (( aligned ( 16 ) ));
- /** Strings block */
- char strings[0];
-} __attribute__ (( packed, aligned ( 16 ) ));
-
-/**
- * iSCSI string block descriptor
+ * iSCSI string buffer
*
* This is an internal structure that we use to keep track of the
* allocation of string data.
*/
struct ibft_strings {
- /** The iBFT containing these strings */
- struct ibft_table *table;
- /** Offset of first free byte within iBFT */
- size_t offset;
- /** Total length of the iBFT */
+ /** Strings data */
+ char *data;
+ /** Starting offset of strings */
+ size_t start;
+ /** Total length */
size_t len;
};
/**
+ * Align structure within iBFT
+ *
+ * @v len Unaligned length (or offset)
+ * @ret len Aligned length (or offset)
+ */
+static inline size_t ibft_align ( size_t len ) {
+
+ return ( ( len + IBFT_ALIGN - 1 ) & ~( IBFT_ALIGN - 1 ) );
+}
+
+/**
* Fill in an IP address field within iBFT
*
* @v ipaddr IP address field
@@ -141,15 +137,29 @@ static const char * ibft_ipaddr ( struct ibft_ipaddr *ipaddr ) {
*/
static char * ibft_alloc_string ( struct ibft_strings *strings,
struct ibft_string *string, size_t len ) {
+ size_t new_len;
+ char *new_data;
+ char *dest;
- if ( ( strings->offset + len ) >= strings->len )
+ /* Extend string data buffer */
+ new_len = ( strings->len + len + 1 /* NUL */ );
+ new_data = realloc ( strings->data, new_len );
+ if ( ! new_data )
return NULL;
+ strings->data = new_data;
- string->offset = cpu_to_le16 ( strings->offset );
+ /* Fill in string field */
+ string->offset = cpu_to_le16 ( strings->start + strings->len );
string->len = cpu_to_le16 ( len );
- strings->offset += ( len + 1 );
- return ( ( ( char * ) strings->table ) + string->offset );
+ /* Zero string */
+ dest = ( strings->data + strings->len );
+ memset ( dest, 0, ( len + 1 /* NUL */ ) );
+
+ /* Update allocated length */
+ strings->len = new_len;
+
+ return dest;
}
/**
@@ -217,8 +227,28 @@ static int ibft_set_string_setting ( struct settings *settings,
*/
static const char * ibft_string ( struct ibft_strings *strings,
struct ibft_string *string ) {
- return ( string->offset ?
- ( ( ( char * ) strings->table ) + string->offset ) : NULL );
+ size_t offset = le16_to_cpu ( string->offset );
+
+ return ( offset ? ( strings->data + offset - strings->start ) : NULL );
+}
+
+/**
+ * Check if network device is required for the iBFT
+ *
+ * @v netdev Network device
+ * @ret is_required Network device is required
+ */
+static int ibft_netdev_is_required ( struct net_device *netdev ) {
+ struct iscsi_session *iscsi;
+ struct sockaddr_tcpip *st_target;
+
+ list_for_each_entry ( iscsi, &ibft_model.descs, desc.list ) {
+ st_target = ( struct sockaddr_tcpip * ) &iscsi->target_sockaddr;
+ if ( tcpip_netdev ( st_target ) == netdev )
+ return 1;
+ }
+
+ return 0;
}
/**
@@ -245,29 +275,33 @@ static int ibft_fill_nic ( struct ibft_nic *nic,
nic->header.length = cpu_to_le16 ( sizeof ( *nic ) );
nic->header.flags = ( IBFT_FL_NIC_BLOCK_VALID |
IBFT_FL_NIC_FIRMWARE_BOOT_SELECTED );
+ DBG ( "iBFT NIC %d is %s\n", nic->header.index, netdev->name );
/* Determine origin of IP address */
fetch_setting ( parent, &ip_setting, &origin, NULL, NULL, 0 );
nic->origin = ( ( origin == parent ) ?
IBFT_NIC_ORIGIN_MANUAL : IBFT_NIC_ORIGIN_DHCP );
- DBG ( "iBFT NIC origin = %d\n", nic->origin );
+ DBG ( "iBFT NIC %d origin = %d\n", nic->header.index, nic->origin );
/* Extract values from configuration settings */
ibft_set_ipaddr_setting ( parent, &nic->ip_address, &ip_setting, 1 );
- DBG ( "iBFT NIC IP = %s\n", ibft_ipaddr ( &nic->ip_address ) );
+ DBG ( "iBFT NIC %d IP = %s\n",
+ nic->header.index, ibft_ipaddr ( &nic->ip_address ) );
ibft_set_ipaddr_setting ( parent, &nic->gateway, &gateway_setting, 1 );
- DBG ( "iBFT NIC gateway = %s\n", ibft_ipaddr ( &nic->gateway ) );
+ DBG ( "iBFT NIC %d gateway = %s\n",
+ nic->header.index, ibft_ipaddr ( &nic->gateway ) );
ibft_set_ipaddr_setting ( NULL, &nic->dns[0], &dns_setting,
( sizeof ( nic->dns ) /
sizeof ( nic->dns[0] ) ) );
ibft_set_ipaddr_setting ( parent, &nic->dhcp, &dhcp_server_setting, 1 );
- DBG ( "iBFT NIC DNS = %s", ibft_ipaddr ( &nic->dns[0] ) );
+ DBG ( "iBFT NIC %d DNS = %s",
+ nic->header.index, ibft_ipaddr ( &nic->dns[0] ) );
DBG ( ", %s\n", ibft_ipaddr ( &nic->dns[1] ) );
if ( ( rc = ibft_set_string_setting ( NULL, strings, &nic->hostname,
&hostname_setting ) ) != 0 )
return rc;
- DBG ( "iBFT NIC hostname = %s\n",
- ibft_string ( strings, &nic->hostname ) );
+ DBG ( "iBFT NIC %d hostname = %s\n",
+ nic->header.index, ibft_string ( strings, &nic->hostname ) );
/* Derive subnet mask prefix from subnet mask */
fetch_ipv4_setting ( parent, &netmask_setting, &netmask_addr );
@@ -277,19 +311,24 @@ static int ibft_fill_nic ( struct ibft_nic *nic,
netmask_addr.s_addr >>= 1;
}
nic->subnet_mask_prefix = netmask_count;
- DBG ( "iBFT NIC subnet = /%d\n", nic->subnet_mask_prefix );
+ DBG ( "iBFT NIC %d subnet = /%d\n",
+ nic->header.index, nic->subnet_mask_prefix );
/* Extract values from net-device configuration */
nic->vlan = cpu_to_le16 ( vlan_tag ( netdev ) );
- DBG ( "iBFT NIC VLAN = %02x\n", le16_to_cpu ( nic->vlan ) );
+ DBG ( "iBFT NIC %d VLAN = %02x\n",
+ nic->header.index, le16_to_cpu ( nic->vlan ) );
if ( ( rc = ll_protocol->eth_addr ( netdev->ll_addr,
nic->mac_address ) ) != 0 ) {
- DBG ( "Could not determine iBFT MAC: %s\n", strerror ( rc ) );
+ DBG ( "Could not determine %s MAC: %s\n",
+ netdev->name, strerror ( rc ) );
return rc;
}
- DBG ( "iBFT NIC MAC = %s\n", eth_ntoa ( nic->mac_address ) );
+ DBG ( "iBFT NIC %d MAC = %s\n",
+ nic->header.index, eth_ntoa ( nic->mac_address ) );
nic->pci_bus_dev_func = cpu_to_le16 ( netdev->dev->desc.location );
- DBG ( "iBFT NIC PCI = %04x\n", le16_to_cpu ( nic->pci_bus_dev_func ) );
+ DBG ( "iBFT NIC %d PCI = %04x\n",
+ nic->header.index, le16_to_cpu ( nic->pci_bus_dev_func ) );
return 0;
}
@@ -299,12 +338,10 @@ static int ibft_fill_nic ( struct ibft_nic *nic,
*
* @v initiator Initiator portion of iBFT
* @v strings iBFT string block descriptor
- * @v iscsi iSCSI session
* @ret rc Return status code
*/
static int ibft_fill_initiator ( struct ibft_initiator *initiator,
- struct ibft_strings *strings,
- struct iscsi_session *iscsi ) {
+ struct ibft_strings *strings ) {
int rc;
/* Fill in common header */
@@ -314,17 +351,58 @@ static int ibft_fill_initiator ( struct ibft_initiator *initiator,
initiator->header.flags = ( IBFT_FL_INITIATOR_BLOCK_VALID |
IBFT_FL_INITIATOR_FIRMWARE_BOOT_SELECTED );
- /* Fill in hostname */
- if ( ( rc = ibft_set_string ( strings, &initiator->initiator_name,
- iscsi->initiator_iqn ) ) != 0 )
+ /* Fill in initiator name */
+ if ( ( rc = ibft_set_string_setting ( NULL, strings,
+ &initiator->initiator_name,
+ &initiator_iqn_setting ) ) != 0 )
return rc;
- DBG ( "iBFT initiator hostname = %s\n",
+ DBG ( "iBFT initiator name = %s\n",
ibft_string ( strings, &initiator->initiator_name ) );
return 0;
}
/**
+ * Fill in Target NIC association
+ *
+ * @v target Target portion of iBFT
+ * @v iscsi iSCSI session
+ * @ret rc Return status code
+ */
+static int ibft_fill_target_nic_association ( struct ibft_target *target,
+ struct iscsi_session *iscsi ) {
+ struct sockaddr_tcpip *st_target =
+ ( struct sockaddr_tcpip * ) &iscsi->target_sockaddr;
+ struct net_device *associated;
+ struct net_device *netdev;
+
+ /* Find network device used to reach target */
+ associated = tcpip_netdev ( st_target );
+ if ( ! associated ) {
+ DBG ( "iBFT target %d has no net device\n",
+ target->header.index );
+ return -EHOSTUNREACH;
+ }
+
+ /* Calculate association */
+ for_each_netdev ( netdev ) {
+ if ( netdev == associated ) {
+ DBG ( "iBFT target %d uses NIC %d (%s)\n",
+ target->header.index, target->nic_association,
+ netdev->name );
+ return 0;
+ }
+ if ( ! ibft_netdev_is_required ( netdev ) )
+ continue;
+ target->nic_association++;
+ }
+
+ DBG ( "iBFT target %d has impossible NIC %s\n",
+ target->header.index, netdev->name );
+ return -EINVAL;
+}
+
+/**
* Fill in Target CHAP portion of iBFT
*
* @v target Target portion of iBFT
@@ -347,12 +425,12 @@ static int ibft_fill_target_chap ( struct ibft_target *target,
if ( ( rc = ibft_set_string ( strings, &target->chap_name,
iscsi->initiator_username ) ) != 0 )
return rc;
- DBG ( "iBFT target username = %s\n",
+ DBG ( "iBFT target %d username = %s\n", target->header.index,
ibft_string ( strings, &target->chap_name ) );
if ( ( rc = ibft_set_string ( strings, &target->chap_secret,
iscsi->initiator_password ) ) != 0 )
return rc;
- DBG ( "iBFT target password = <redacted>\n" );
+ DBG ( "iBFT target %d password = <redacted>\n", target->header.index );
return 0;
}
@@ -382,12 +460,13 @@ static int ibft_fill_target_reverse_chap ( struct ibft_target *target,
if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_name,
iscsi->target_username ) ) != 0 )
return rc;
- DBG ( "iBFT target reverse username = %s\n",
+ DBG ( "iBFT target %d reverse username = %s\n", target->header.index,
ibft_string ( strings, &target->chap_name ) );
if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_secret,
iscsi->target_password ) ) != 0 )
return rc;
- DBG ( "iBFT target reverse password = <redacted>\n" );
+ DBG ( "iBFT target %d reverse password = <redacted>\n",
+ target->header.index );
return 0;
}
@@ -403,6 +482,8 @@ static int ibft_fill_target_reverse_chap ( struct ibft_target *target,
static int ibft_fill_target ( struct ibft_target *target,
struct ibft_strings *strings,
struct iscsi_session *iscsi ) {
+ struct sockaddr_tcpip *st_target =
+ ( struct sockaddr_tcpip * ) &iscsi->target_sockaddr;
struct sockaddr_in *sin_target =
( struct sockaddr_in * ) &iscsi->target_sockaddr;
int rc;
@@ -416,17 +497,21 @@ static int ibft_fill_target ( struct ibft_target *target,
/* Fill in Target values */
ibft_set_ipaddr ( &target->ip_address, sin_target->sin_addr );
- DBG ( "iBFT target IP = %s\n", ibft_ipaddr ( &target->ip_address ) );
- target->socket = cpu_to_le16 ( ntohs ( sin_target->sin_port ) );
- DBG ( "iBFT target port = %d\n", target->socket );
+ DBG ( "iBFT target %d IP = %s\n",
+ target->header.index, ibft_ipaddr ( &target->ip_address ) );
+ target->socket = cpu_to_le16 ( ntohs ( st_target->st_port ) );
+ DBG ( "iBFT target %d port = %d\n",
+ target->header.index, target->socket );
memcpy ( &target->boot_lun, &iscsi->lun, sizeof ( target->boot_lun ) );
- DBG ( "iBFT target boot LUN = " SCSI_LUN_FORMAT "\n",
- SCSI_LUN_DATA ( target->boot_lun ) );
+ DBG ( "iBFT target %d boot LUN = " SCSI_LUN_FORMAT "\n",
+ target->header.index, SCSI_LUN_DATA ( target->boot_lun ) );
if ( ( rc = ibft_set_string ( strings, &target->target_name,
iscsi->target_iqn ) ) != 0 )
return rc;
- DBG ( "iBFT target name = %s\n",
+ DBG ( "iBFT target %d name = %s\n", target->header.index,
ibft_string ( strings, &target->target_name ) );
+ if ( ( rc = ibft_fill_target_nic_association ( target, iscsi ) ) != 0 )
+ return rc;
if ( ( rc = ibft_fill_target_chap ( target, strings, iscsi ) ) != 0 )
return rc;
if ( ( rc = ibft_fill_target_reverse_chap ( target, strings,
@@ -437,62 +522,159 @@ static int ibft_fill_target ( struct ibft_target *target,
}
/**
- * Fill in iBFT
+ * Check if iBFT descriptor is complete
*
- * @v iscsi iSCSI session
- * @v acpi ACPI table
- * @v len Length of ACPI table
+ * @v desc ACPI descriptor
* @ret rc Return status code
*/
-int ibft_describe ( struct iscsi_session *iscsi,
- struct acpi_description_header *acpi,
- size_t len ) {
- struct ipxe_ibft *ibft =
- container_of ( acpi, struct ipxe_ibft, table.acpi );
- struct ibft_strings strings = {
- .table = &ibft->table,
- .offset = offsetof ( typeof ( *ibft ), strings ),
- .len = len,
- };
+static int ibft_complete ( struct acpi_descriptor *desc ) {
+ struct iscsi_session *iscsi =
+ container_of ( desc, struct iscsi_session, desc );
+
+ /* Fail if we do not yet have the target address */
+ if ( ! iscsi->target_sockaddr.sa_family )
+ return -EAGAIN;
+
+ return 0;
+}
+
+/**
+ * Install iBFT
+ *
+ * @v install Installation method
+ * @ret rc Return status code
+ */
+static int ibft_install ( int ( * install ) ( struct acpi_header *acpi ) ) {
struct net_device *netdev;
+ struct iscsi_session *iscsi;
+ struct ibft_table *table;
+ struct ibft_initiator *initiator;
+ struct ibft_nic *nic;
+ struct ibft_target *target;
+ struct ibft_strings strings;
+ struct acpi_header *acpi;
+ void *data;
+ unsigned int targets = 0;
+ unsigned int pairs = 0;
+ size_t offset = 0;
+ size_t table_len;
+ size_t control_len;
+ size_t initiator_offset;
+ size_t nic_offset;
+ size_t target_offset;
+ size_t strings_offset;
+ size_t len;
+ unsigned int i;
int rc;
- /* Ugly hack. Now that we have a generic interface mechanism
- * that can support ioctls, we can potentially eliminate this.
- */
- netdev = last_opened_netdev();
- if ( ! netdev ) {
- DBGC ( iscsi, "iSCSI %p cannot guess network device\n",
- iscsi );
- return -ENODEV;
+ /* Calculate table sizes and offsets */
+ list_for_each_entry ( iscsi, &ibft_model.descs, desc.list )
+ targets++;
+ pairs = ( sizeof ( table->control.pair ) /
+ sizeof ( table->control.pair[0] ) );
+ if ( pairs < targets )
+ pairs = targets;
+ offset = offsetof ( typeof ( *table ), control.pair );
+ offset += ( pairs * sizeof ( table->control.pair[0] ) );
+ table_len = offset;
+ control_len = ( table_len - offsetof ( typeof ( *table ), control ) );
+ offset = ibft_align ( offset );
+ initiator_offset = offset;
+ offset += ibft_align ( sizeof ( *initiator ) );
+ nic_offset = offset;
+ offset += ( pairs * ibft_align ( sizeof ( *nic ) ) );
+ target_offset = offset;
+ offset += ( pairs * ibft_align ( sizeof ( *target ) ) );
+ strings_offset = offset;
+ strings.data = NULL;
+ strings.start = strings_offset;
+ strings.len = 0;
+ len = offset;
+
+ /* Allocate table */
+ data = zalloc ( len );
+ if ( ! data ) {
+ rc = -ENOMEM;
+ goto err_alloc;
}
- /* Fill in ACPI header */
- ibft->table.acpi.signature = cpu_to_le32 ( IBFT_SIG );
- ibft->table.acpi.length = cpu_to_le32 ( len );
- ibft->table.acpi.revision = 1;
-
/* Fill in Control block */
- ibft->table.control.header.structure_id = IBFT_STRUCTURE_ID_CONTROL;
- ibft->table.control.header.version = 1;
- ibft->table.control.header.length =
- cpu_to_le16 ( sizeof ( ibft->table.control ) );
- ibft->table.control.initiator =
- cpu_to_le16 ( offsetof ( typeof ( *ibft ), initiator ) );
- ibft->table.control.nic_0 =
- cpu_to_le16 ( offsetof ( typeof ( *ibft ), nic ) );
- ibft->table.control.target_0 =
- cpu_to_le16 ( offsetof ( typeof ( *ibft ), target ) );
-
- /* Fill in NIC, Initiator and Target blocks */
- if ( ( rc = ibft_fill_nic ( &ibft->nic, &strings, netdev ) ) != 0 )
- return rc;
- if ( ( rc = ibft_fill_initiator ( &ibft->initiator, &strings,
- iscsi ) ) != 0 )
- return rc;
- if ( ( rc = ibft_fill_target ( &ibft->target, &strings,
- iscsi ) ) != 0 )
- return rc;
+ table = data;
+ table->control.header.structure_id = IBFT_STRUCTURE_ID_CONTROL;
+ table->control.header.version = 1;
+ table->control.header.length = cpu_to_le16 ( control_len );
+
+ /* Fill in Initiator block */
+ initiator = ( data + initiator_offset );
+ table->control.initiator = cpu_to_le16 ( initiator_offset );
+ if ( ( rc = ibft_fill_initiator ( initiator, &strings ) ) != 0 )
+ goto err_initiator;
+
+ /* Fill in NIC blocks */
+ i = 0;
+ for_each_netdev ( netdev ) {
+ if ( ! ibft_netdev_is_required ( netdev ) )
+ continue;
+ assert ( i < pairs );
+ table->control.pair[i].nic = nic_offset;
+ nic = ( data + nic_offset );
+ nic->header.index = i;
+ if ( ( rc = ibft_fill_nic ( nic, &strings, netdev ) ) != 0 )
+ goto err_nic;
+ i++;
+ nic_offset += ibft_align ( sizeof ( *nic ) );
+ }
- return 0;
+ /* Fill in Target blocks */
+ i = 0;
+ list_for_each_entry ( iscsi, &ibft_model.descs, desc.list ) {
+ assert ( i < pairs );
+ table->control.pair[i].target = target_offset;
+ target = ( data + target_offset );
+ target->header.index = i;
+ if ( ( rc = ibft_fill_target ( target, &strings, iscsi ) ) != 0)
+ goto err_target;
+ i++;
+ target_offset += ibft_align ( sizeof ( *target ) );
+ }
+
+ /* Reallocate table to include space for strings */
+ len += strings.len;
+ acpi = realloc ( data, len );
+ if ( ! acpi )
+ goto err_realloc;
+ data = NULL;
+
+ /* Fill in ACPI header */
+ acpi->signature = cpu_to_le32 ( IBFT_SIG );
+ acpi->length = cpu_to_le32 ( len );
+ acpi->revision = 1;
+
+ /* Append strings */
+ memcpy ( ( ( ( void * ) acpi ) + strings_offset ), strings.data,
+ strings.len );
+
+ /* Install ACPI table */
+ if ( ( rc = install ( acpi ) ) != 0 ) {
+ DBG ( "iBFT could not install: %s\n", strerror ( rc ) );
+ goto err_install;
+ }
+
+ err_install:
+ free ( acpi );
+ err_realloc:
+ err_target:
+ err_nic:
+ err_initiator:
+ free ( data );
+ err_alloc:
+ free ( strings.data );
+ return rc;
}
+
+/** iBFT model */
+struct acpi_model ibft_model __acpi_model = {
+ .descs = LIST_HEAD_INIT ( ibft_model.descs ),
+ .complete = ibft_complete,
+ .install = ibft_install,
+};
diff --git a/src/drivers/block/srp.c b/src/drivers/block/srp.c
index 7edf69ac..ab481251 100644
--- a/src/drivers/block/srp.c
+++ b/src/drivers/block/srp.c
@@ -113,13 +113,6 @@ struct srp_device {
/** Login completed successfully */
int logged_in;
- /** Initiator port ID (for boot firmware table) */
- union srp_port_id initiator;
- /** Target port ID (for boot firmware table) */
- union srp_port_id target;
- /** SCSI LUN (for boot firmware table) */
- struct scsi_lun lun;
-
/** List of active commands */
struct list_head commands;
};
@@ -684,61 +677,6 @@ static size_t srpdev_window ( struct srp_device *srpdev ) {
return ( srpdev->logged_in ? ~( ( size_t ) 0 ) : 0 );
}
-/**
- * A (transport-independent) sBFT created by iPXE
- */
-struct ipxe_sbft {
- /** The table header */
- struct sbft_table table;
- /** The SCSI subtable */
- struct sbft_scsi_subtable scsi;
- /** The SRP subtable */
- struct sbft_srp_subtable srp;
-} __attribute__ (( packed, aligned ( 16 ) ));
-
-/**
- * Describe SRP device in an ACPI table
- *
- * @v srpdev SRP device
- * @v acpi ACPI table
- * @v len Length of ACPI table
- * @ret rc Return status code
- */
-static int srpdev_describe ( struct srp_device *srpdev,
- struct acpi_description_header *acpi,
- size_t len ) {
- struct ipxe_sbft *sbft =
- container_of ( acpi, struct ipxe_sbft, table.acpi );
- int rc;
-
- /* Sanity check */
- if ( len < sizeof ( *sbft ) )
- return -ENOBUFS;
-
- /* Populate table */
- sbft->table.acpi.signature = cpu_to_le32 ( SBFT_SIG );
- sbft->table.acpi.length = cpu_to_le32 ( sizeof ( *sbft ) );
- sbft->table.acpi.revision = 1;
- sbft->table.scsi_offset =
- cpu_to_le16 ( offsetof ( typeof ( *sbft ), scsi ) );
- memcpy ( &sbft->scsi.lun, &srpdev->lun, sizeof ( sbft->scsi.lun ) );
- sbft->table.srp_offset =
- cpu_to_le16 ( offsetof ( typeof ( *sbft ), srp ) );
- memcpy ( &sbft->srp.initiator, &srpdev->initiator,
- sizeof ( sbft->srp.initiator ) );
- memcpy ( &sbft->srp.target, &srpdev->target,
- sizeof ( sbft->srp.target ) );
-
- /* Ask transport layer to describe transport-specific portions */
- if ( ( rc = acpi_describe ( &srpdev->socket, acpi, len ) ) != 0 ) {
- DBGC ( srpdev, "SRP %p cannot describe transport layer: %s\n",
- srpdev, strerror ( rc ) );
- return rc;
- }
-
- return 0;
-}
-
/** SRP device socket interface operations */
static struct interface_operation srpdev_socket_op[] = {
INTF_OP ( xfer_deliver, struct srp_device *, srpdev_deliver ),
@@ -755,7 +693,6 @@ static struct interface_operation srpdev_scsi_op[] = {
INTF_OP ( scsi_command, struct srp_device *, srpdev_scsi_command ),
INTF_OP ( xfer_window, struct srp_device *, srpdev_window ),
INTF_OP ( intf_close, struct srp_device *, srpdev_close ),
- INTF_OP ( acpi_describe, struct srp_device *, srpdev_describe ),
};
/** SRP device SCSI interface descriptor */
@@ -797,11 +734,6 @@ int srp_open ( struct interface *block, struct interface *socket,
ntohl ( target->dwords[0] ), ntohl ( target->dwords[1] ),
ntohl ( target->dwords[2] ), ntohl ( target->dwords[3] ) );
- /* Preserve parameters required for boot firmware table */
- memcpy ( &srpdev->initiator, initiator, sizeof ( srpdev->initiator ) );
- memcpy ( &srpdev->target, target, sizeof ( srpdev->target ) );
- memcpy ( &srpdev->lun, lun, sizeof ( srpdev->lun ) );
-
/* Attach to socket interface and initiate login */
intf_plug_plug ( &srpdev->socket, socket );
tag = srp_new_tag ( srpdev );
diff --git a/src/include/ipxe/acpi.h b/src/include/ipxe/acpi.h
index 17d29b9d..f87b8ae9 100644
--- a/src/include/ipxe/acpi.h
+++ b/src/include/ipxe/acpi.h
@@ -10,8 +10,12 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
+#include <byteswap.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/list.h>
#include <ipxe/interface.h>
#include <ipxe/uaccess.h>
+#include <ipxe/tables.h>
/**
* An ACPI description header
@@ -19,7 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* This is the structure common to the start of all ACPI system
* description tables.
*/
-struct acpi_description_header {
+struct acpi_header {
/** ACPI signature (4 ASCII characters) */
uint32_t signature;
/** Length of table, in bytes, including header */
@@ -41,6 +45,22 @@ struct acpi_description_header {
} __attribute__ (( packed ));
/**
+ * Transcribe ACPI table signature (for debugging)
+ *
+ * @v signature ACPI table signature
+ * @ret name ACPI table signature name
+ */
+static inline const char * acpi_name ( uint32_t signature ) {
+ static union {
+ uint32_t signature;
+ char name[5];
+ } u;
+
+ u.signature = cpu_to_le32 ( signature );
+ return u.name;
+}
+
+/**
* Build ACPI signature
*
* @v a First character of ACPI signature
@@ -87,7 +107,7 @@ struct acpi_rsdp {
/** ACPI Root System Description Table (RSDT) */
struct acpi_rsdt {
/** ACPI header */
- struct acpi_description_header acpi;
+ struct acpi_header acpi;
/** ACPI table entries */
uint32_t entry[0];
} __attribute__ (( packed ));
@@ -98,7 +118,7 @@ struct acpi_rsdt {
/** Fixed ACPI Description Table (FADT) */
struct acpi_fadt {
/** ACPI header */
- struct acpi_description_header acpi;
+ struct acpi_header acpi;
/** Physical address of FACS */
uint32_t facs;
/** Physical address of DSDT */
@@ -122,17 +142,70 @@ struct acpi_fadt {
/** Secondary System Description Table (SSDT) signature */
#define SSDT_SIGNATURE ACPI_SIGNATURE ( 'S', 'S', 'D', 'T' )
-extern int acpi_describe ( struct interface *interface,
- struct acpi_description_header *acpi, size_t len );
+/** An ACPI descriptor (used to construct ACPI tables) */
+struct acpi_descriptor {
+ /** Reference count of containing object */
+ struct refcnt *refcnt;
+ /** Table model */
+ struct acpi_model *model;
+ /** List of ACPI descriptors for this model */
+ struct list_head list;
+};
+
+/**
+ * Initialise ACPI descriptor
+ *
+ * @v desc ACPI descriptor
+ * @v model Table model
+ * @v refcnt Reference count
+ */
+static inline __attribute__ (( always_inline )) void
+acpi_init ( struct acpi_descriptor *desc, struct acpi_model *model,
+ struct refcnt *refcnt ) {
+
+ desc->refcnt = refcnt;
+ desc->model = model;
+ INIT_LIST_HEAD ( &desc->list );
+}
+
+/** An ACPI table model */
+struct acpi_model {
+ /** List of descriptors */
+ struct list_head descs;
+ /**
+ * Check if ACPI descriptor is complete
+ *
+ * @v desc ACPI descriptor
+ * @ret rc Return status code
+ */
+ int ( * complete ) ( struct acpi_descriptor *desc );
+ /**
+ * Install ACPI tables
+ *
+ * @v install Installation method
+ * @ret rc Return status code
+ */
+ int ( * install ) ( int ( * install ) ( struct acpi_header *acpi ) );
+};
+
+/** ACPI models */
+#define ACPI_MODELS __table ( struct acpi_model, "acpi_models" )
+
+/** Declare an ACPI model */
+#define __acpi_model __table_entry ( ACPI_MODELS, 01 )
+
+extern struct acpi_descriptor *
+acpi_describe ( struct interface *interface );
#define acpi_describe_TYPE( object_type ) \
- typeof ( int ( object_type, \
- struct acpi_description_header *acpi, \
- size_t len ) )
+ typeof ( struct acpi_descriptor * ( object_type ) )
-extern void acpi_fix_checksum ( struct acpi_description_header *acpi );
+extern void acpi_fix_checksum ( struct acpi_header *acpi );
extern userptr_t acpi_find_rsdt ( userptr_t ebda );
extern userptr_t acpi_find ( userptr_t rsdt, uint32_t signature,
unsigned int index );
extern int acpi_sx ( userptr_t rsdt, uint32_t signature );
+extern void acpi_add ( struct acpi_descriptor *desc );
+extern void acpi_del ( struct acpi_descriptor *desc );
+extern int acpi_install ( int ( * install ) ( struct acpi_header *acpi ) );
#endif /* _IPXE_ACPI_H */
diff --git a/src/include/ipxe/aoe.h b/src/include/ipxe/aoe.h
index 0c656e7c..a51044d1 100644
--- a/src/include/ipxe/aoe.h
+++ b/src/include/ipxe/aoe.h
@@ -117,7 +117,7 @@ struct aoehdr {
*/
struct abft_table {
/** ACPI header */
- struct acpi_description_header acpi;
+ struct acpi_header acpi;
/** AoE shelf */
uint16_t shelf;
/** AoE slot */
diff --git a/src/include/ipxe/ibft.h b/src/include/ipxe/ibft.h
index 35f15105..51ce781a 100644
--- a/src/include/ipxe/ibft.h
+++ b/src/include/ipxe/ibft.h
@@ -49,6 +49,9 @@ FILE_LICENCE ( BSD2 );
/** iSCSI Boot Firmware Table signature */
#define IBFT_SIG ACPI_SIGNATURE ( 'i', 'B', 'F', 'T' )
+/** Alignment of structures within iBFT */
+#define IBFT_ALIGN 16
+
/** An offset from the start of the iBFT */
typedef uint16_t ibft_off_t;
@@ -98,6 +101,20 @@ struct ibft_header {
} __attribute__ (( packed ));
/**
+ * iBFT NIC and Target offset pair
+ *
+ * There is no implicit relation between the NIC and the Target, but
+ * using this structure simplifies the table construction code while
+ * matching the expected table layout.
+ */
+struct ibft_offset_pair {
+ /** Offset to NIC structure */
+ ibft_off_t nic;
+ /** Offset to Target structure */
+ ibft_off_t target;
+} __attribute__ (( packed ));
+
+/**
* iBFT Control structure
*
*/
@@ -108,14 +125,8 @@ struct ibft_control {
uint16_t extensions;
/** Offset to Initiator structure */
ibft_off_t initiator;
- /** Offset to NIC structure for NIC 0 */
- ibft_off_t nic_0;
- /** Offset to Target structure for target 0 */
- ibft_off_t target_0;
- /** Offset to NIC structure for NIC 1 */
- ibft_off_t nic_1;
- /** Offset to Target structure for target 1 */
- ibft_off_t target_1;
+ /** Offsets to NIC and Target structures */
+ struct ibft_offset_pair pair[2];
} __attribute__ (( packed ));
/** Structure ID for Control section */
@@ -262,18 +273,13 @@ struct ibft_target {
*/
struct ibft_table {
/** ACPI header */
- struct acpi_description_header acpi;
+ struct acpi_header acpi;
/** Reserved */
uint8_t reserved[12];
/** Control structure */
struct ibft_control control;
} __attribute__ (( packed ));
-struct iscsi_session;
-struct net_device;
-
-extern int ibft_describe ( struct iscsi_session *iscsi,
- struct acpi_description_header *acpi,
- size_t len );
+extern struct acpi_model ibft_model __acpi_model;
#endif /* _IPXE_IBFT_H */
diff --git a/src/include/ipxe/iscsi.h b/src/include/ipxe/iscsi.h
index c75ff418..966cf52b 100644
--- a/src/include/ipxe/iscsi.h
+++ b/src/include/ipxe/iscsi.h
@@ -16,6 +16,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/refcnt.h>
#include <ipxe/xfer.h>
#include <ipxe/process.h>
+#include <ipxe/acpi.h>
+#include <ipxe/settings.h>
/** Default iSCSI port */
#define ISCSI_PORT 3260
@@ -647,6 +649,8 @@ struct iscsi_session {
struct sockaddr target_sockaddr;
/** SCSI LUN (for boot firmware table) */
struct scsi_lun lun;
+ /** ACPI descriptor */
+ struct acpi_descriptor desc;
};
/** iSCSI session is currently in the security negotiation phase */
@@ -697,4 +701,7 @@ struct iscsi_session {
/** Default initiator IQN prefix */
#define ISCSI_DEFAULT_IQN_PREFIX "iqn.2010-04.org.ipxe"
+extern const struct setting
+initiator_iqn_setting __setting ( SETTING_SANBOOT_EXTRA, initiator-iqn );
+
#endif /* _IPXE_ISCSI_H */
diff --git a/src/include/ipxe/sanboot.h b/src/include/ipxe/sanboot.h
index 64b665a5..8737bbc0 100644
--- a/src/include/ipxe/sanboot.h
+++ b/src/include/ipxe/sanboot.h
@@ -18,6 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/retry.h>
#include <ipxe/process.h>
#include <ipxe/blockdev.h>
+#include <ipxe/acpi.h>
#include <config/sanboot.h>
/** A SAN path */
@@ -37,6 +38,9 @@ struct san_path {
struct process process;
/** Path status */
int path_rc;
+
+ /** ACPI descriptor (if applicable) */
+ struct acpi_descriptor *desc;
};
/** A SAN device */
@@ -48,6 +52,8 @@ struct san_device {
/** Drive number */
unsigned int drive;
+ /** Flags */
+ unsigned int flags;
/** Command interface */
struct interface command;
@@ -83,6 +89,12 @@ struct san_device {
struct san_path path[0];
};
+/** SAN device flags */
+enum san_device_flags {
+ /** Device should not be included in description tables */
+ SAN_NO_DESCRIBE = 0x0001,
+};
+
/**
* Calculate static inline sanboot API function name
*
@@ -126,9 +138,11 @@ struct san_device {
* @v drive Drive number
* @v uris List of URIs
* @v count Number of URIs
+ * @v flags Flags
* @ret drive Drive number, or negative error
*/
-int san_hook ( unsigned int drive, struct uri **uris, unsigned int count );
+int san_hook ( unsigned int drive, struct uri **uris, unsigned int count,
+ unsigned int flags );
/**
* Unhook SAN device
@@ -146,12 +160,11 @@ void san_unhook ( unsigned int drive );
int san_boot ( unsigned int drive );
/**
- * Describe SAN device for SAN-booted operating system
+ * Describe SAN devices for SAN-booted operating system
*
- * @v drive Drive number
* @ret rc Return status code
*/
-int san_describe ( unsigned int drive );
+int san_describe ( void );
extern struct list_head san_devices;
@@ -230,7 +243,8 @@ extern int sandev_rw ( struct san_device *sandev, uint64_t lba,
userptr_t buffer, size_t len ) );
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 int register_sandev ( struct san_device *sandev, unsigned int drive,
+ unsigned int flags );
extern void unregister_sandev ( struct san_device *sandev );
extern unsigned int san_default_drive ( void );
diff --git a/src/include/ipxe/srp.h b/src/include/ipxe/srp.h
index 8d7f799c..3abb0995 100644
--- a/src/include/ipxe/srp.h
+++ b/src/include/ipxe/srp.h
@@ -790,7 +790,7 @@ typedef uint16_t sbft_off_t;
*/
struct sbft_table {
/** ACPI header */
- struct acpi_description_header acpi;
+ struct acpi_header acpi;
/** Offset to SCSI subtable */
sbft_off_t scsi_offset;
/** Offset to SRP subtable */
diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c
index 9679fc0d..fa2271b3 100644
--- a/src/interface/efi/efi_block.c
+++ b/src/interface/efi/efi_block.c
@@ -254,10 +254,11 @@ static void efi_block_connect ( struct san_device *sandev ) {
* @v drive Drive number
* @v uris List of URIs
* @v count Number of URIs
+ * @v flags Flags
* @ret drive Drive number, or negative error
*/
static int efi_block_hook ( unsigned int drive, struct uri **uris,
- unsigned int count ) {
+ unsigned int count, unsigned int flags ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
EFI_DEVICE_PATH_PROTOCOL *end;
struct efi_block_vendor_path *vendor;
@@ -301,7 +302,6 @@ static int efi_block_hook ( unsigned int drive, struct uri **uris,
rc = -ENOMEM;
goto err_alloc;
}
- sandev->drive = drive;
block = sandev->priv;
block->sandev = sandev;
block->media.MediaPresent = 1;
@@ -331,12 +331,12 @@ static int efi_block_hook ( unsigned int drive, struct uri **uris,
end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
end->Length[0] = sizeof ( *end );
DBGC ( sandev, "EFIBLK %#02x has device path %s\n",
- sandev->drive, efi_devpath_text ( block->path ) );
+ drive, efi_devpath_text ( block->path ) );
/* Register SAN device */
- if ( ( rc = register_sandev ( sandev ) ) != 0 ) {
+ if ( ( rc = register_sandev ( sandev, drive, flags ) ) != 0 ) {
DBGC ( sandev, "EFIBLK %#02x could not register: %s\n",
- sandev->drive, strerror ( rc ) );
+ drive, strerror ( rc ) );
goto err_register;
}
@@ -408,85 +408,105 @@ static void efi_block_unhook ( unsigned int drive ) {
sandev_put ( sandev );
}
+/** An installed ACPI table */
+struct efi_acpi_table {
+ /** List of installed tables */
+ struct list_head list;
+ /** Table key */
+ UINTN key;
+};
+
+/** List of installed ACPI tables */
+static LIST_HEAD ( efi_acpi_tables );
+
/**
- * Describe EFI block device
+ * Install ACPI table
*
- * @v drive Drive number
+ * @v hdr ACPI description header
* @ret rc Return status code
*/
-static int efi_block_describe ( unsigned int drive ) {
- static union {
- /** ACPI header */
- struct acpi_description_header acpi;
- /** Padding */
- char pad[768];
- } xbftab;
- static UINTN key;
- struct san_device *sandev;
- struct san_path *sanpath;
- size_t len;
+static int efi_block_install ( struct acpi_header *hdr ) {
+ size_t len = le32_to_cpu ( hdr->length );
+ struct efi_acpi_table *installed;
EFI_STATUS efirc;
int rc;
- /* Find SAN device */
- sandev = sandev_find ( drive );
- if ( ! sandev ) {
- DBG ( "EFIBLK cannot find drive %#02x\n", drive );
- return -ENODEV;
+ /* Allocate installed table record */
+ installed = zalloc ( sizeof ( *installed ) );
+ if ( ! installed ) {
+ rc = -ENOMEM;
+ goto err_alloc;
}
+ /* Fill in common parameters */
+ strncpy ( hdr->oem_id, "FENSYS", sizeof ( hdr->oem_id ) );
+ strncpy ( hdr->oem_table_id, "iPXE", sizeof ( hdr->oem_table_id ) );
+
+ /* Fix up ACPI checksum */
+ acpi_fix_checksum ( hdr );
+
+ /* Install table */
+ if ( ( efirc = acpi->InstallAcpiTable ( acpi, hdr, len,
+ &installed->key ) ) != 0 ){
+ rc = -EEFI ( efirc );
+ DBGC ( acpi, "EFIBLK could not install %s: %s\n",
+ acpi_name ( hdr->signature ), strerror ( rc ) );
+ DBGC_HDA ( acpi, 0, hdr, len );
+ goto err_install;
+ }
+
+ /* Add to list of installed tables */
+ list_add_tail ( &installed->list, &efi_acpi_tables );
+
+ DBGC ( acpi, "EFIBLK installed %s as ACPI table %#lx:\n",
+ acpi_name ( hdr->signature ),
+ ( ( unsigned long ) installed->key ) );
+ DBGC_HDA ( acpi, 0, hdr, len );
+ return 0;
+
+ list_del ( &installed->list );
+ err_install:
+ free ( installed );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Describe EFI block devices
+ *
+ * @ret rc Return status code
+ */
+static int efi_block_describe ( void ) {
+ struct efi_acpi_table *installed;
+ struct efi_acpi_table *tmp;
+ UINTN key;
+ EFI_STATUS efirc;
+ int rc;
+
/* Sanity check */
if ( ! acpi ) {
- DBGC ( sandev, "EFIBLK %#02x has no ACPI table protocol\n",
- sandev->drive );
+ DBG ( "EFIBLK has no ACPI table protocol\n" );
return -ENOTSUP;
}
- /* Remove existing table, if any */
- if ( key ) {
+ /* Uninstall any existing ACPI tables */
+ list_for_each_entry_safe ( installed, tmp, &efi_acpi_tables, list ) {
+ key = installed->key;
if ( ( efirc = acpi->UninstallAcpiTable ( acpi, key ) ) != 0 ) {
rc = -EEFI ( efirc );
- DBGC ( sandev, "EFIBLK %#02x could not uninstall ACPI "
- "table: %s\n", sandev->drive, strerror ( rc ) );
+ DBGC ( acpi, "EFIBLK could not uninstall ACPI table "
+ "%#lx: %s\n", ( ( unsigned long ) key ),
+ strerror ( rc ) );
/* Continue anyway */
}
- key = 0;
- }
-
- /* Reopen block device if necessary */
- 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 ) );
-
- /* Fill in common parameters */
- strncpy ( xbftab.acpi.oem_id, "FENSYS",
- sizeof ( xbftab.acpi.oem_id ) );
- strncpy ( xbftab.acpi.oem_table_id, "iPXE",
- sizeof ( xbftab.acpi.oem_table_id ) );
-
- /* Fill in remaining parameters */
- 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 ) );
- return rc;
+ list_del ( &installed->list );
+ free ( installed );
}
- len = le32_to_cpu ( xbftab.acpi.length );
-
- /* Fix up ACPI checksum */
- acpi_fix_checksum ( &xbftab.acpi );
- /* Install table */
- if ( ( efirc = acpi->InstallAcpiTable ( acpi, &xbftab, len,
- &key ) ) != 0 ) {
- rc = -EEFI ( efirc );
- DBGC ( sandev, "EFIBLK %#02x could not install ACPI table: "
- "%s\n", sandev->drive, strerror ( rc ) );
+ /* Install ACPI tables */
+ if ( ( rc = acpi_install ( efi_block_install ) ) != 0 ) {
+ DBGC ( acpi, "EFIBLK could not install ACPI tables: %s\n",
+ strerror ( rc ) );
return rc;
}
diff --git a/src/net/aoe.c b/src/net/aoe.c
index 2da8655b..3a6611d0 100644
--- a/src/net/aoe.c
+++ b/src/net/aoe.c
@@ -53,6 +53,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
FEATURE ( FEATURE_PROTOCOL, "AoE", DHCP_EB_FEATURE_AOE, 1 );
struct net_protocol aoe_protocol __net_protocol;
+struct acpi_model abft_model __acpi_model;
/******************************************************************************
*
@@ -91,6 +92,9 @@ struct aoe_device {
struct interface config;
/** Device is configued */
int configured;
+
+ /** ACPI descriptor */
+ struct acpi_descriptor desc;
};
/** An AoE command */
@@ -790,32 +794,13 @@ static struct device * aoedev_identify_device ( struct aoe_device *aoedev ) {
}
/**
- * Describe AoE device in an ACPI table
+ * Get AoE ACPI descriptor
*
* @v aoedev AoE device
- * @v acpi ACPI table
- * @v len Length of ACPI table
- * @ret rc Return status code
+ * @ret desc ACPI descriptor
*/
-static int aoedev_describe ( struct aoe_device *aoedev,
- struct acpi_description_header *acpi,
- size_t len ) {
- struct abft_table *abft =
- container_of ( acpi, struct abft_table, acpi );
-
- /* Sanity check */
- if ( len < sizeof ( *abft ) )
- return -ENOBUFS;
-
- /* Populate table */
- abft->acpi.signature = cpu_to_le32 ( ABFT_SIG );
- abft->acpi.length = cpu_to_le32 ( sizeof ( *abft ) );
- abft->acpi.revision = 1;
- abft->shelf = cpu_to_le16 ( aoedev->major );
- abft->slot = aoedev->minor;
- memcpy ( abft->mac, aoedev->netdev->ll_addr, sizeof ( abft->mac ) );
-
- return 0;
+static struct acpi_descriptor * aoedev_describe ( struct aoe_device *aoedev ) {
+ return &aoedev->desc;
}
/** AoE device ATA interface operations */
@@ -869,6 +854,7 @@ static int aoedev_open ( struct interface *parent, struct net_device *netdev,
aoedev->minor = minor;
memcpy ( aoedev->target, netdev->ll_broadcast,
netdev->ll_protocol->ll_addr_len );
+ acpi_init ( &aoedev->desc, &abft_model, &aoedev->refcnt );
/* Initiate configuration */
if ( ( rc = aoedev_cfg_command ( aoedev, &aoedev->config ) ) < 0 ) {
@@ -1059,3 +1045,61 @@ struct uri_opener aoe_uri_opener __uri_opener = {
.scheme = "aoe",
.open = aoe_open,
};
+
+/******************************************************************************
+ *
+ * AoE boot firmware table (aBFT)
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Check if AoE boot firmware table descriptor is complete
+ *
+ * @v desc ACPI descriptor
+ * @ret rc Return status code
+ */
+static int abft_complete ( struct acpi_descriptor *desc __unused ) {
+ return 0;
+}
+
+/**
+ * Install AoE boot firmware table(s)
+ *
+ * @v install Installation method
+ * @ret rc Return status code
+ */
+static int abft_install ( int ( * install ) ( struct acpi_header *acpi ) ) {
+ struct aoe_device *aoedev;
+ struct abft_table abft;
+ int rc;
+
+ list_for_each_entry ( aoedev, &abft_model.descs, desc.list ) {
+
+ /* Populate table */
+ memset ( &abft, 0, sizeof ( abft ) );
+ abft.acpi.signature = cpu_to_le32 ( ABFT_SIG );
+ abft.acpi.length = cpu_to_le32 ( sizeof ( abft ) );
+ abft.acpi.revision = 1;
+ abft.shelf = cpu_to_le16 ( aoedev->major );
+ abft.slot = aoedev->minor;
+ memcpy ( abft.mac, aoedev->netdev->ll_addr,
+ sizeof ( abft.mac ) );
+
+ /* Install table */
+ if ( ( rc = install ( &abft.acpi ) ) != 0 ) {
+ DBGC ( aoedev, "AoE %s could not install aBFT: %s\n",
+ aoedev_name ( aoedev ), strerror ( rc ) );
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+/** aBFT model */
+struct acpi_model abft_model __acpi_model = {
+ .descs = LIST_HEAD_INIT ( abft_model.descs ),
+ .complete = abft_complete,
+ .install = abft_install,
+};
diff --git a/src/net/fcp.c b/src/net/fcp.c
index 930bf7dd..d92cfdcf 100644
--- a/src/net/fcp.c
+++ b/src/net/fcp.c
@@ -844,25 +844,6 @@ static size_t fcpdev_window ( struct fcp_device *fcpdev ) {
}
/**
- * Describe FCP device in an ACPI table
- *
- * @v fcpdev FCP device
- * @v acpi ACPI table
- * @v len Length of ACPI table
- * @ret rc Return status code
- */
-static int fcpdev_acpi_describe ( struct fcp_device *fcpdev,
- struct acpi_description_header *acpi,
- size_t len ) {
-
- DBGC ( fcpdev, "FCP %p cannot yet describe device in an ACPI table\n",
- fcpdev );
- ( void ) acpi;
- ( void ) len;
- return 0;
-}
-
-/**
* Describe FCP device using EDD
*
* @v fcpdev FCP device
@@ -917,7 +898,6 @@ static struct interface_operation fcpdev_scsi_op[] = {
INTF_OP ( scsi_command, struct fcp_device *, fcpdev_scsi_command ),
INTF_OP ( xfer_window, struct fcp_device *, fcpdev_window ),
INTF_OP ( intf_close, struct fcp_device *, fcpdev_close ),
- INTF_OP ( acpi_describe, struct fcp_device *, fcpdev_acpi_describe ),
INTF_OP ( edd_describe, struct fcp_device *, fcpdev_edd_describe ),
INTF_OP ( identify_device, struct fcp_device *,
fcpdev_identify_device ),
diff --git a/src/net/infiniband/ib_srp.c b/src/net/infiniband/ib_srp.c
index 3b4914ab..cf1ef3bf 100644
--- a/src/net/infiniband/ib_srp.c
+++ b/src/net/infiniband/ib_srp.c
@@ -60,6 +60,8 @@ FILE_LICENCE ( BSD2 );
#define EINFO_EINVAL_RP_TOO_SHORT __einfo_uniqify \
( EINFO_EINVAL, 0x04, "Root path too short" )
+struct acpi_model ib_sbft_model __acpi_model;
+
/******************************************************************************
*
* IB SRP devices
@@ -67,6 +69,20 @@ FILE_LICENCE ( BSD2 );
******************************************************************************
*/
+/**
+ * An IB SRP sBFT created by iPXE
+ */
+struct ipxe_ib_sbft {
+ /** The table header */
+ struct sbft_table table;
+ /** The SCSI subtable */
+ struct sbft_scsi_subtable scsi;
+ /** The SRP subtable */
+ struct sbft_srp_subtable srp;
+ /** The Infiniband subtable */
+ struct sbft_ib_subtable ib;
+};
+
/** An Infiniband SRP device */
struct ib_srp_device {
/** Reference count */
@@ -80,10 +96,10 @@ struct ib_srp_device {
/** Infiniband device */
struct ib_device *ibdev;
- /** Destination GID (for boot firmware table) */
- union ib_gid dgid;
- /** Service ID (for boot firmware table) */
- union ib_guid service_id;
+ /** ACPI descriptor */
+ struct acpi_descriptor desc;
+ /** Boot firmware table parameters */
+ struct ipxe_ib_sbft sbft;
};
/**
@@ -113,43 +129,15 @@ static void ib_srp_close ( struct ib_srp_device *ib_srp, int rc ) {
}
/**
- * Describe IB SRP device in an ACPI table
+ * Get IB SRP ACPI descriptor
*
- * @v srpdev SRP device
- * @v acpi ACPI table
- * @v len Length of ACPI table
- * @ret rc Return status code
+ * @v ib_srp IB SRP device
+ * @ret desc ACPI descriptor
*/
-static int ib_srp_describe ( struct ib_srp_device *ib_srp,
- struct acpi_description_header *acpi,
- size_t len ) {
- struct ib_device *ibdev = ib_srp->ibdev;
- struct sbft_table *sbft =
- container_of ( acpi, struct sbft_table, acpi );
- struct sbft_ib_subtable *ib_sbft;
- size_t used;
-
- /* Sanity check */
- if ( acpi->signature != SBFT_SIG )
- return -EINVAL;
-
- /* Append IB subtable to existing table */
- used = le32_to_cpu ( sbft->acpi.length );
- sbft->ib_offset = cpu_to_le16 ( used );
- ib_sbft = ( ( ( void * ) sbft ) + used );
- used += sizeof ( *ib_sbft );
- if ( used > len )
- return -ENOBUFS;
- sbft->acpi.length = cpu_to_le32 ( used );
-
- /* Populate subtable */
- memcpy ( &ib_sbft->sgid, &ibdev->gid, sizeof ( ib_sbft->sgid ) );
- memcpy ( &ib_sbft->dgid, &ib_srp->dgid, sizeof ( ib_sbft->dgid ) );
- memcpy ( &ib_sbft->service_id, &ib_srp->service_id,
- sizeof ( ib_sbft->service_id ) );
- ib_sbft->pkey = cpu_to_le16 ( ibdev->pkey );
+static struct acpi_descriptor *
+ib_srp_describe ( struct ib_srp_device *ib_srp ) {
- return 0;
+ return &ib_srp->desc;
}
/** IB SRP CMRC interface operations */
@@ -188,6 +176,7 @@ static int ib_srp_open ( struct interface *block, struct ib_device *ibdev,
union srp_port_id *initiator,
union srp_port_id *target, struct scsi_lun *lun ) {
struct ib_srp_device *ib_srp;
+ struct ipxe_ib_sbft *sbft;
int rc;
/* Allocate and initialise structure */
@@ -200,13 +189,19 @@ static int ib_srp_open ( struct interface *block, struct ib_device *ibdev,
intf_init ( &ib_srp->srp, &ib_srp_srp_desc, &ib_srp->refcnt );
intf_init ( &ib_srp->cmrc, &ib_srp_cmrc_desc, &ib_srp->refcnt );
ib_srp->ibdev = ibdev_get ( ibdev );
+ acpi_init ( &ib_srp->desc, &ib_sbft_model, &ib_srp->refcnt );
DBGC ( ib_srp, "IBSRP %p for " IB_GID_FMT " " IB_GUID_FMT "\n",
ib_srp, IB_GID_ARGS ( dgid ), IB_GUID_ARGS ( service_id ) );
/* Preserve parameters required for boot firmware table */
- memcpy ( &ib_srp->dgid, dgid, sizeof ( ib_srp->dgid ) );
- memcpy ( &ib_srp->service_id, service_id,
- sizeof ( ib_srp->service_id ) );
+ sbft = &ib_srp->sbft;
+ memcpy ( &sbft->scsi.lun, lun, sizeof ( sbft->scsi.lun ) );
+ memcpy ( &sbft->srp.initiator, initiator,
+ sizeof ( sbft->srp.initiator ) );
+ memcpy ( &sbft->srp.target, target, sizeof ( sbft->srp.target ) );
+ memcpy ( &sbft->ib.dgid, dgid, sizeof ( sbft->ib.dgid ) );
+ memcpy ( &sbft->ib.service_id, service_id,
+ sizeof ( sbft->ib.service_id ) );
/* Open CMRC socket */
if ( ( rc = ib_cmrc_open ( &ib_srp->cmrc, ibdev, dgid,
@@ -579,3 +574,67 @@ struct uri_opener ib_srp_uri_opener __uri_opener = {
.scheme = "ib_srp",
.open = ib_srp_open_uri,
};
+
+/******************************************************************************
+ *
+ * IB SRP boot firmware table (sBFT)
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Check if IB SRP boot firmware table descriptor is complete
+ *
+ * @v desc ACPI descriptor
+ * @ret rc Return status code
+ */
+static int ib_sbft_complete ( struct acpi_descriptor *desc __unused ) {
+ return 0;
+}
+
+/**
+ * Install IB SRP boot firmware table(s)
+ *
+ * @v install Installation method
+ * @ret rc Return status code
+ */
+static int ib_sbft_install ( int ( * install ) ( struct acpi_header *acpi ) ) {
+ struct ib_srp_device *ib_srp;
+ struct ipxe_ib_sbft *sbft;
+ struct ib_device *ibdev;
+ int rc;
+
+ list_for_each_entry ( ib_srp, &ib_sbft_model.descs, desc.list ) {
+
+ /* Complete table */
+ sbft = &ib_srp->sbft;
+ ibdev = ib_srp->ibdev;
+ sbft->table.acpi.signature = cpu_to_le32 ( SBFT_SIG );
+ sbft->table.acpi.length = cpu_to_le32 ( sizeof ( *sbft ) );
+ sbft->table.acpi.revision = 1;
+ sbft->table.scsi_offset =
+ cpu_to_le16 ( offsetof ( typeof ( *sbft ), scsi ) );
+ sbft->table.srp_offset =
+ cpu_to_le16 ( offsetof ( typeof ( *sbft ), srp ) );
+ sbft->table.ib_offset =
+ cpu_to_le16 ( offsetof ( typeof ( *sbft ), ib ) );
+ memcpy ( &sbft->ib.sgid, &ibdev->gid, sizeof ( sbft->ib.sgid ));
+ sbft->ib.pkey = cpu_to_le16 ( ibdev->pkey );
+
+ /* Install table */
+ if ( ( rc = install ( &sbft->table.acpi ) ) != 0 ) {
+ DBGC ( ib_srp, "IBSRP %p could not install sBFT: %s\n",
+ ib_srp, strerror ( rc ) );
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+/** IB sBFT model */
+struct acpi_model ib_sbft_model __acpi_model = {
+ .descs = LIST_HEAD_INIT ( ib_sbft_model.descs ),
+ .complete = ib_sbft_complete,
+ .install = ib_sbft_install,
+};
diff --git a/src/net/tcp/httpblock.c b/src/net/tcp/httpblock.c
index e124ad2d..1abd6b34 100644
--- a/src/net/tcp/httpblock.c
+++ b/src/net/tcp/httpblock.c
@@ -114,21 +114,3 @@ int http_block_read_capacity ( struct http_transaction *http,
err_open:
return rc;
}
-
-/**
- * Describe device in ACPI table
- *
- * @v http HTTP transaction
- * @v acpi ACPI table
- * @v len Length of ACPI table
- * @ret rc Return status code
- */
-int http_acpi_describe ( struct http_transaction *http,
- struct acpi_description_header *acpi, size_t len ) {
-
- DBGC ( http, "HTTP %p cannot yet describe device in an ACPI table\n",
- http );
- ( void ) acpi;
- ( void ) len;
- return 0;
-}
diff --git a/src/net/tcp/httpcore.c b/src/net/tcp/httpcore.c
index ec527c64..ce53a212 100644
--- a/src/net/tcp/httpcore.c
+++ b/src/net/tcp/httpcore.c
@@ -509,28 +509,11 @@ __weak int http_block_read_capacity ( struct http_transaction *http __unused,
return -ENOTSUP;
}
-/**
- * Describe device in ACPI table (when HTTP block device support is not present)
- *
- * @v http HTTP transaction
- * @v acpi ACPI table
- * @v len Length of ACPI table
- * @ret rc Return status code
- */
-__weak int http_acpi_describe ( struct http_transaction *http __unused,
- struct acpi_description_header *acpi __unused,
- size_t len __unused ) {
-
- return -ENOTSUP;
-}
-
/** HTTP data transfer interface operations */
static struct interface_operation http_xfer_operations[] = {
INTF_OP ( block_read, struct http_transaction *, http_block_read ),
INTF_OP ( block_read_capacity, struct http_transaction *,
http_block_read_capacity ),
- INTF_OP ( acpi_describe, struct http_transaction *,
- http_acpi_describe ),
INTF_OP ( xfer_window_changed, struct http_transaction *, http_step ),
INTF_OP ( intf_close, struct http_transaction *, http_close ),
};
diff --git a/src/net/tcp/iscsi.c b/src/net/tcp/iscsi.c
index 1e6fd1f5..7de4a7bf 100644
--- a/src/net/tcp/iscsi.c
+++ b/src/net/tcp/iscsi.c
@@ -1810,12 +1810,23 @@ static int iscsi_scsi_command ( struct iscsi_session *iscsi,
return iscsi->itt;
}
+/**
+ * Get iSCSI ACPI descriptor
+ *
+ * @v iscsi iSCSI session
+ * @ret desc ACPI descriptor
+ */
+static struct acpi_descriptor * iscsi_describe ( struct iscsi_session *iscsi ) {
+
+ return &iscsi->desc;
+}
+
/** iSCSI SCSI command-issuing interface operations */
static struct interface_operation iscsi_control_op[] = {
INTF_OP ( scsi_command, struct iscsi_session *, iscsi_scsi_command ),
INTF_OP ( xfer_window, struct iscsi_session *, iscsi_scsi_window ),
INTF_OP ( intf_close, struct iscsi_session *, iscsi_close ),
- INTF_OP ( acpi_describe, struct iscsi_session *, ibft_describe ),
+ INTF_OP ( acpi_describe, struct iscsi_session *, iscsi_describe ),
};
/** iSCSI SCSI command-issuing interface descriptor */
@@ -2064,6 +2075,7 @@ static int iscsi_open ( struct interface *parent, struct uri *uri ) {
intf_init ( &iscsi->socket, &iscsi_socket_desc, &iscsi->refcnt );
process_init_stopped ( &iscsi->process, &iscsi_process_desc,
&iscsi->refcnt );
+ acpi_init ( &iscsi->desc, &ibft_model, &iscsi->refcnt );
/* Parse root path */
if ( ( rc = iscsi_parse_root_path ( iscsi, uri->opaque ) ) != 0 )
diff --git a/src/usr/autoboot.c b/src/usr/autoboot.c
index a0c79351..10ccdc1d 100644
--- a/src/usr/autoboot.c
+++ b/src/usr/autoboot.c
@@ -128,7 +128,9 @@ int uriboot ( struct uri *filename, struct uri **root_paths,
/* Hook SAN device, if applicable */
if ( root_path_count ) {
- drive = san_hook ( drive, root_paths, root_path_count );
+ drive = san_hook ( drive, root_paths, root_path_count,
+ ( ( flags & URIBOOT_NO_SAN_DESCRIBE ) ?
+ SAN_NO_DESCRIBE : 0 ) );
if ( drive < 0 ) {
rc = drive;
printf ( "Could not open SAN device: %s\n",
@@ -140,9 +142,9 @@ int uriboot ( struct uri *filename, struct uri **root_paths,
/* Describe SAN device, if applicable */
if ( ! ( flags & URIBOOT_NO_SAN_DESCRIBE ) ) {
- if ( ( rc = san_describe ( drive ) ) != 0 ) {
- printf ( "Could not describe SAN device %#02x: %s\n",
- drive, strerror ( rc ) );
+ if ( ( rc = san_describe() ) != 0 ) {
+ printf ( "Could not describe SAN devices: %s\n",
+ strerror ( rc ) );
goto err_san_describe;
}
}