david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[block] Describe all SAN devices via ACPI tables

Describe all SAN devices via ACPI tables such as the iBFT.  For tables
that can describe only a single device (i.e. the aBFT and sBFT), one
table is installed per device.  For multi-device tables (i.e. the
iBFT), all devices are described in a single table.

An underlying SAN device connection may be closed at the time that we
need to construct an ACPI table.  We therefore introduce the concept
of an "ACPI descriptor" which enables the SAN boot code to maintain an
opaque pointer to the underlying object, and an "ACPI model" which can
build tables from a list of such descriptors.  This separates the
lifecycles of ACPI descriptions from the lifecycles of the block
device interfaces, and allows for construction of the ACPI tables even
if the block device interface has been closed.

For a multipath SAN device, iPXE will wait until sufficient
information is available to describe all devices but will not wait for
all paths to connect successfully.  For example: with a multipath
iSCSI boot iPXE will wait until at least one path has become available
and name resolution has completed on all other paths.  We do this
since the iBFT has to include IP addresses rather than DNS names.  We
will commence booting without waiting for the inactive paths to either
become available or close; this avoids unnecessary boot delays.

Note that the Linux kernel will refuse to accept an iBFT with more
than two NIC or target structures.  We therefore describe only the
NICs that are actually required in order to reach the described
targets.  Any iBFT with at most two targets is therefore guaranteed to
describe at most two NICs.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown 2017-03-27 18:20:34 +03:00
parent 414b4fc9c5
commit 7cfdd769aa
21 changed files with 930 additions and 491 deletions

View File

@ -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
/** The boot firmware table generated by iPXE */
static union xbft_table __bss16 ( xbftab ) __attribute__ (( aligned ( 16 ) ));
/** Alignment of boot firmware table entries */
#define XBFTAB_ALIGN 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;
struct acpi_header *installed;
size_t len;
/* Find drive */
sandev = sandev_find ( drive );
if ( ! sandev ) {
DBG ( "INT13 cannot find drive %02x\n", drive );
return -ENODEV;
/* 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 );
/* Clear table */
memset ( &xbftab, 0, sizeof ( xbftab ) );
/* 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 ( xbftab.acpi.oem_id, "FENSYS",
sizeof ( xbftab.acpi.oem_id ) );
strncpy ( xbftab.acpi.oem_table_id, "iPXE",
sizeof ( xbftab.acpi.oem_table_id ) );
strncpy ( installed->oem_id, "FENSYS",
sizeof ( installed->oem_id ) );
strncpy ( installed->oem_table_id, "iPXE",
sizeof ( installed->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 ) );
/* 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;
}
/**
* 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;
/* 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;
}

View File

@ -42,28 +42,12 @@ 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;
}

View File

@ -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;
@ -101,14 +101,27 @@ static int dummy_san_boot ( unsigned int drive __unused ) {
return -EOPNOTSUPP;
}
/**
* Install ACPI table
*
* @v acpi ACPI description header
* @ret rc Return status code
*/
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
*
* @v drive Drive number
* @ret rc Return status code
*/
static int dummy_san_describe ( unsigned int drive __unused ) {
static int dummy_san_describe ( void ) {
return 0;
return acpi_install ( dummy_install );
}
PROVIDE_SANBOOT ( dummy, san_hook, dummy_san_hook );

View File

@ -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;
}

View File

@ -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 );
@ -606,6 +617,72 @@ int sandev_rw ( struct san_device *sandev, uint64_t lba,
return 0;
}
/**
* 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
*
@ -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 );
}

View File

@ -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,37 +56,31 @@ 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
*
@ -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,16 +351,57 @@ 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
*
@ -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,
};
struct net_device *netdev;
int rc;
static int ibft_complete ( struct acpi_descriptor *desc ) {
struct iscsi_session *iscsi =
container_of ( desc, struct iscsi_session, desc );
/* 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;
}
/* 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;
/* 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;
/* 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 Control block */
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 ) );
}
/* 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,
};

View File

@ -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 );

View File

@ -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 */
@ -40,6 +44,22 @@ struct acpi_description_header {
uint32_t asl_compiler_revision;
} __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
*
@ -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 );
#define acpi_describe_TYPE( object_type ) \
typeof ( int ( object_type, \
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;
};
extern void acpi_fix_checksum ( struct acpi_description_header *acpi );
/**
* 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 ( struct acpi_descriptor * ( object_type ) )
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 */

View File

@ -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 */

View File

@ -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;
@ -97,6 +100,20 @@ struct ibft_header {
uint8_t flags;
} __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 */

View File

@ -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 */

View File

@ -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 );

View File

@ -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 */

View File

@ -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;
list_del ( &installed->list );
free ( installed );
}
/* 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;
}
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;
}

View File

@ -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,
};

View File

@ -843,25 +843,6 @@ static size_t fcpdev_window ( struct fcp_device *fcpdev ) {
~( ( size_t ) 0 ) : 0 );
}
/**
* 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
*
@ -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 ),

View File

@ -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;
static struct acpi_descriptor *
ib_srp_describe ( struct ib_srp_device *ib_srp ) {
/* 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 );
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,
};

View File

@ -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;
}

View File

@ -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 ),
};

View File

@ -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 )

View File

@ -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;
}
}