iPXE
|
iSCSI boot firmware table More...
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/pci.h>
#include <ipxe/acpi.h>
#include <ipxe/in.h>
#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>
Go to the source code of this file.
Data Structures | |
struct | ibft_strings |
iSCSI string buffer More... | |
Functions | |
FILE_LICENCE (BSD2) | |
static size_t | ibft_align (size_t len) |
Align structure within iBFT. | |
static void | ibft_set_ipaddr (struct ibft_ipaddr *ipaddr, struct in_addr in) |
Fill in an IP address field within iBFT. | |
static void | ibft_set_ipaddr_setting (struct settings *settings, struct ibft_ipaddr *ipaddr, const struct setting *setting, unsigned int count) |
Fill in an IP address within iBFT from configuration setting. | |
static const char * | ibft_ipaddr (struct ibft_ipaddr *ipaddr) |
Read IP address from iBFT (for debugging) | |
static char * | ibft_alloc_string (struct ibft_strings *strings, struct ibft_string *string, size_t len) |
Allocate a string within iBFT. | |
static int | ibft_set_string (struct ibft_strings *strings, struct ibft_string *string, const char *data) |
Fill in a string field within iBFT. | |
static int | ibft_set_string_setting (struct settings *settings, struct ibft_strings *strings, struct ibft_string *string, const struct setting *setting) |
Fill in a string field within iBFT from configuration setting. | |
static const char * | ibft_string (struct ibft_strings *strings, struct ibft_string *string) |
Read string from iBFT (for debugging) | |
static int | ibft_netdev_is_required (struct net_device *netdev) |
Check if network device is required for the iBFT. | |
static int | ibft_fill_nic (struct ibft_nic *nic, struct ibft_strings *strings, struct net_device *netdev) |
Fill in NIC portion of iBFT. | |
static int | ibft_fill_initiator (struct ibft_initiator *initiator, struct ibft_strings *strings, const char *initiator_iqn) |
Fill in Initiator portion of iBFT. | |
static int | ibft_fill_target_nic_association (struct ibft_target *target, struct iscsi_session *iscsi) |
Fill in Target NIC association. | |
static int | ibft_fill_target_chap (struct ibft_target *target, struct ibft_strings *strings, struct iscsi_session *iscsi) |
Fill in Target CHAP portion of iBFT. | |
static int | ibft_fill_target_reverse_chap (struct ibft_target *target, struct ibft_strings *strings, struct iscsi_session *iscsi) |
Fill in Target Reverse CHAP portion of iBFT. | |
static int | ibft_fill_target (struct ibft_target *target, struct ibft_strings *strings, struct iscsi_session *iscsi) |
Fill in Target portion of iBFT. | |
static int | ibft_complete (struct acpi_descriptor *desc) |
Check if iBFT descriptor is complete. | |
static int | ibft_install (int(*install)(struct acpi_header *acpi)) |
Install iBFT. | |
Variables | |
struct acpi_model ibft_model | __acpi_model |
iBFT model |
iSCSI boot firmware table
The information in this file is derived from the document "iSCSI Boot Firmware Table (iBFT)" as published by IBM at
ftp://ftp.software.ibm.com/systems/support/system_x_pdf/ibm_iscsi_boot_firmware_table_v1.02.pdf
Definition in file ibft.c.
FILE_LICENCE | ( | BSD2 | ) |
static size_t ibft_align | ( | size_t | len | ) | [inline, static] |
Align structure within iBFT.
len | Unaligned length (or offset) |
len | Aligned length (or offset) |
Definition at line 79 of file ibft.c.
References IBFT_ALIGN.
Referenced by ibft_install().
{ return ( ( len + IBFT_ALIGN - 1 ) & ~( IBFT_ALIGN - 1 ) ); }
static void ibft_set_ipaddr | ( | struct ibft_ipaddr * | ipaddr, |
struct in_addr | in | ||
) | [static] |
Fill in an IP address field within iBFT.
ipaddr | IP address field |
in | IPv4 address |
Definition at line 90 of file ibft.c.
References ibft_ipaddr::in, in, memset(), ibft_ipaddr::ones, and in_addr::s_addr.
Referenced by ibft_fill_target(), and ibft_set_ipaddr_setting().
static void ibft_set_ipaddr_setting | ( | struct settings * | settings, |
struct ibft_ipaddr * | ipaddr, | ||
const struct setting * | setting, | ||
unsigned int | count | ||
) | [static] |
Fill in an IP address within iBFT from configuration setting.
settings | Parent settings block, or NULL |
ipaddr | IP address field |
setting | Configuration setting |
count | Maximum number of IP addresses |
Definition at line 106 of file ibft.c.
References count, fetch_ipv4_array_setting(), and ibft_set_ipaddr().
Referenced by ibft_fill_nic().
{ struct in_addr in[count]; unsigned int i; fetch_ipv4_array_setting ( settings, setting, in, count ); for ( i = 0 ; i < count ; i++ ) { ibft_set_ipaddr ( &ipaddr[i], in[i] ); } }
static const char* ibft_ipaddr | ( | struct ibft_ipaddr * | ipaddr | ) | [static] |
Read IP address from iBFT (for debugging)
strings | iBFT string block descriptor |
string | String field |
ipaddr | IP address string |
Definition at line 126 of file ibft.c.
References ibft_ipaddr::in, and inet_ntoa().
static char* ibft_alloc_string | ( | struct ibft_strings * | strings, |
struct ibft_string * | string, | ||
size_t | len | ||
) | [static] |
Allocate a string within iBFT.
strings | iBFT string block descriptor |
string | String field to fill in |
len | Length of string to allocate (excluding NUL) |
dest | String destination, or NULL |
Definition at line 138 of file ibft.c.
References cpu_to_le16, ibft_strings::data, dest, ibft_strings::len, memset(), NULL, realloc(), and ibft_strings::start.
Referenced by ibft_set_string(), and ibft_set_string_setting().
{ size_t new_len; char *new_data; char *dest; /* 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; /* Fill in string field */ string->offset = cpu_to_le16 ( strings->start + strings->len ); string->len = cpu_to_le16 ( len ); /* Zero string */ dest = ( strings->data + strings->len ); memset ( dest, 0, ( len + 1 /* NUL */ ) ); /* Update allocated length */ strings->len = new_len; return dest; }
static int ibft_set_string | ( | struct ibft_strings * | strings, |
struct ibft_string * | string, | ||
const char * | data | ||
) | [static] |
Fill in a string field within iBFT.
strings | iBFT string block descriptor |
string | String field |
data | String to fill in, or NULL |
rc | Return status code |
Definition at line 173 of file ibft.c.
References dest, ENOBUFS, ibft_alloc_string(), strcpy(), and strlen().
Referenced by ibft_fill_initiator(), ibft_fill_target(), ibft_fill_target_chap(), and ibft_fill_target_reverse_chap().
static int ibft_set_string_setting | ( | struct settings * | settings, |
struct ibft_strings * | strings, | ||
struct ibft_string * | string, | ||
const struct setting * | setting | ||
) | [static] |
Fill in a string field within iBFT from configuration setting.
settings | Parent settings block, or NULL |
strings | iBFT string block descriptor |
string | String field |
setting | Configuration setting |
rc | Return status code |
Definition at line 197 of file ibft.c.
References dest, ENOBUFS, fetch_setting(), fetch_string_setting(), ibft_alloc_string(), len, NULL, and origin.
Referenced by ibft_fill_nic().
{ struct settings *origin; struct setting fetched; int len; char *dest; len = fetch_setting ( settings, setting, &origin, &fetched, NULL, 0 ); if ( len < 0 ) { string->offset = 0; string->len = 0; return 0; } dest = ibft_alloc_string ( strings, string, len ); if ( ! dest ) return -ENOBUFS; fetch_string_setting ( origin, &fetched, dest, ( len + 1 )); return 0; }
static const char* ibft_string | ( | struct ibft_strings * | strings, |
struct ibft_string * | string | ||
) | [static] |
Read string from iBFT (for debugging)
strings | iBFT string block descriptor |
string | String field |
data | String content (or "<empty>") |
Definition at line 228 of file ibft.c.
References ibft_strings::data, le16_to_cpu, NULL, ibft_string::offset, offset, and ibft_strings::start.
static int ibft_netdev_is_required | ( | struct net_device * | netdev | ) | [static] |
Check if network device is required for the iBFT.
netdev | Network device |
is_required | Network device is required |
Definition at line 241 of file ibft.c.
References list_for_each_entry, netdev, iscsi_session::target_sockaddr, and tcpip_netdev().
Referenced by ibft_fill_target_nic_association(), and ibft_install().
{ 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; }
static int ibft_fill_nic | ( | struct ibft_nic * | nic, |
struct ibft_strings * | strings, | ||
struct net_device * | netdev | ||
) | [static] |
Fill in NIC portion of iBFT.
nic | NIC portion of iBFT |
strings | iBFT string block descriptor |
netdev | Network device |
rc | Return status code |
Definition at line 262 of file ibft.c.
References cpu_to_le16, DBG, device::desc, net_device::dev, ibft_nic::dhcp, ibft_nic::dns, ll_protocol::eth_addr, eth_ntoa(), fetch_ipv4_setting(), fetch_setting(), ibft_header::flags, ibft_nic::gateway, ibft_nic::header, ibft_nic::hostname, IBFT_FL_NIC_BLOCK_VALID, IBFT_FL_NIC_FIRMWARE_BOOT_SELECTED, IBFT_NIC_ORIGIN_DHCP, IBFT_NIC_ORIGIN_MANUAL, ibft_set_ipaddr_setting(), ibft_set_string_setting(), IBFT_STRUCTURE_ID_NIC, ibft_header::index, ibft_nic::ip_address, le16_to_cpu, ibft_header::length, net_device::ll_addr, net_device::ll_protocol, device_description::location, ibft_nic::mac_address, net_device::name, netdev_settings(), NULL, origin, ibft_nic::origin, settings::parent, ibft_nic::pci_bus_dev_func, rc, in_addr::s_addr, strerror(), ibft_header::structure_id, ibft_nic::subnet_mask_prefix, ibft_header::version, ibft_nic::vlan, and vlan_tag().
Referenced by ibft_install().
{ struct ll_protocol *ll_protocol = netdev->ll_protocol; struct in_addr netmask_addr = { 0 }; unsigned int netmask_count = 0; struct settings *parent = netdev_settings ( netdev ); struct settings *origin; int rc; /* Fill in common header */ nic->header.structure_id = IBFT_STRUCTURE_ID_NIC; nic->header.version = 1; 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 %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 %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 %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 %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 %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 ); while ( netmask_addr.s_addr ) { if ( netmask_addr.s_addr & 0x1 ) netmask_count++; netmask_addr.s_addr >>= 1; } nic->subnet_mask_prefix = netmask_count; 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 %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 %s MAC: %s\n", netdev->name, strerror ( rc ) ); return rc; } 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 %d PCI = %04x\n", nic->header.index, le16_to_cpu ( nic->pci_bus_dev_func ) ); return 0; }
static int ibft_fill_initiator | ( | struct ibft_initiator * | initiator, |
struct ibft_strings * | strings, | ||
const char * | initiator_iqn | ||
) | [static] |
Fill in Initiator portion of iBFT.
initiator | Initiator portion of iBFT |
strings | iBFT string block descriptor |
initiator_iqn | Initiator IQN |
rc | Return status code |
Definition at line 344 of file ibft.c.
References cpu_to_le16, DBG, ibft_header::flags, ibft_initiator::header, IBFT_FL_INITIATOR_BLOCK_VALID, IBFT_FL_INITIATOR_FIRMWARE_BOOT_SELECTED, ibft_set_string(), IBFT_STRUCTURE_ID_INITIATOR, ibft_initiator::initiator_name, ibft_header::length, rc, ibft_header::structure_id, and ibft_header::version.
Referenced by ibft_install().
{ int rc; /* Fill in common header */ initiator->header.structure_id = IBFT_STRUCTURE_ID_INITIATOR; initiator->header.version = 1; initiator->header.length = cpu_to_le16 ( sizeof ( *initiator ) ); initiator->header.flags = ( IBFT_FL_INITIATOR_BLOCK_VALID | IBFT_FL_INITIATOR_FIRMWARE_BOOT_SELECTED ); /* Fill in initiator name */ if ( ( rc = ibft_set_string ( strings, &initiator->initiator_name, initiator_iqn ) ) != 0 ) return rc; DBG ( "iBFT initiator name = %s\n", ibft_string ( strings, &initiator->initiator_name ) ); return 0; }
static int ibft_fill_target_nic_association | ( | struct ibft_target * | target, |
struct iscsi_session * | iscsi | ||
) | [static] |
Fill in Target NIC association.
target | Target portion of iBFT |
iscsi | iSCSI session |
rc | Return status code |
Definition at line 373 of file ibft.c.
References DBG, EHOSTUNREACH, EINVAL, for_each_netdev, ibft_target::header, ibft_netdev_is_required(), ibft_header::index, net_device::name, netdev, ibft_target::nic_association, iscsi_session::target_sockaddr, and tcpip_netdev().
Referenced by ibft_fill_target().
{ 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; }
static int ibft_fill_target_chap | ( | struct ibft_target * | target, |
struct ibft_strings * | strings, | ||
struct iscsi_session * | iscsi | ||
) | [static] |
Fill in Target CHAP portion of iBFT.
target | Target portion of iBFT |
strings | iBFT string block descriptor |
iscsi | iSCSI session |
rc | Return status code |
Definition at line 414 of file ibft.c.
References assert, ibft_target::chap_name, ibft_target::chap_secret, ibft_target::chap_type, DBG, ibft_target::header, IBFT_CHAP_ONE_WAY, ibft_set_string(), ibft_header::index, iscsi_session::initiator_password, iscsi_session::initiator_username, ISCSI_STATUS_AUTH_FORWARD_REQUIRED, rc, and iscsi_session::status.
Referenced by ibft_fill_target().
{ int rc; if ( ! ( iscsi->status & ISCSI_STATUS_AUTH_FORWARD_REQUIRED ) ) return 0; assert ( iscsi->initiator_username ); assert ( iscsi->initiator_password ); target->chap_type = IBFT_CHAP_ONE_WAY; if ( ( rc = ibft_set_string ( strings, &target->chap_name, iscsi->initiator_username ) ) != 0 ) return rc; 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 %d password = <redacted>\n", target->header.index ); return 0; }
static int ibft_fill_target_reverse_chap | ( | struct ibft_target * | target, |
struct ibft_strings * | strings, | ||
struct iscsi_session * | iscsi | ||
) | [static] |
Fill in Target Reverse CHAP portion of iBFT.
target | Target portion of iBFT |
strings | iBFT string block descriptor |
iscsi | iSCSI session |
rc | Return status code |
Definition at line 447 of file ibft.c.
References assert, ibft_target::chap_name, ibft_target::chap_type, DBG, ibft_target::header, IBFT_CHAP_MUTUAL, ibft_set_string(), ibft_header::index, iscsi_session::initiator_password, iscsi_session::initiator_username, ISCSI_STATUS_AUTH_REVERSE_REQUIRED, rc, ibft_target::reverse_chap_name, ibft_target::reverse_chap_secret, iscsi_session::status, iscsi_session::target_password, and iscsi_session::target_username.
Referenced by ibft_fill_target().
{ int rc; if ( ! ( iscsi->status & ISCSI_STATUS_AUTH_REVERSE_REQUIRED ) ) return 0; assert ( iscsi->initiator_username ); assert ( iscsi->initiator_password ); assert ( iscsi->target_username ); assert ( iscsi->target_password ); target->chap_type = IBFT_CHAP_MUTUAL; if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_name, iscsi->target_username ) ) != 0 ) return rc; 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 %d reverse password = <redacted>\n", target->header.index ); return 0; }
static int ibft_fill_target | ( | struct ibft_target * | target, |
struct ibft_strings * | strings, | ||
struct iscsi_session * | iscsi | ||
) | [static] |
Fill in Target portion of iBFT.
target | Target portion of iBFT |
strings | iBFT string block descriptor |
iscsi | iSCSI session |
rc | Return status code |
Definition at line 483 of file ibft.c.
References ibft_target::boot_lun, cpu_to_le16, DBG, ibft_header::flags, ibft_target::header, ibft_fill_target_chap(), ibft_fill_target_nic_association(), ibft_fill_target_reverse_chap(), IBFT_FL_TARGET_BLOCK_VALID, IBFT_FL_TARGET_FIRMWARE_BOOT_SELECTED, ibft_set_ipaddr(), ibft_set_string(), IBFT_STRUCTURE_ID_TARGET, ibft_header::index, ibft_target::ip_address, ibft_header::length, iscsi_session::lun, memcpy(), ntohs, rc, SCSI_LUN_DATA, SCSI_LUN_FORMAT, ibft_target::socket, sockaddr_tcpip::st_port, ibft_header::structure_id, iscsi_session::target_iqn, ibft_target::target_name, iscsi_session::target_sockaddr, and ibft_header::version.
Referenced by ibft_install().
{ struct sockaddr_tcpip *st_target = ( struct sockaddr_tcpip * ) &iscsi->target_sockaddr; struct sockaddr_in *sin_target = ( struct sockaddr_in * ) &iscsi->target_sockaddr; int rc; /* Fill in common header */ target->header.structure_id = IBFT_STRUCTURE_ID_TARGET; target->header.version = 1; target->header.length = cpu_to_le16 ( sizeof ( *target ) ); target->header.flags = ( IBFT_FL_TARGET_BLOCK_VALID | IBFT_FL_TARGET_FIRMWARE_BOOT_SELECTED ); /* Fill in Target values */ ibft_set_ipaddr ( &target->ip_address, sin_target->sin_addr ); 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 %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 %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, iscsi ) ) != 0 ) return rc; return 0; }
static int ibft_complete | ( | struct acpi_descriptor * | desc | ) | [static] |
Check if iBFT descriptor is complete.
desc | ACPI descriptor |
rc | Return status code |
Definition at line 531 of file ibft.c.
References container_of, EAGAIN, sockaddr::sa_family, and iscsi_session::target_sockaddr.
{ 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; }
static int ibft_install | ( | int(*)(struct acpi_header *acpi) | install | ) | [static] |
Install iBFT.
install | Installation method |
rc | Return status code |
Definition at line 548 of file ibft.c.
References acpi, assert, control, ibft_table::control, cpu_to_le16, cpu_to_le32, ibft_strings::data, data, DBG, ENOMEM, for_each_netdev, free, ibft_control::header, ibft_nic::header, ibft_target::header, ibft_align(), ibft_fill_initiator(), ibft_fill_nic(), ibft_fill_target(), ibft_netdev_is_required(), IBFT_SIG, IBFT_STRUCTURE_ID_CONTROL, ibft_header::index, ibft_control::initiator, iscsi_session::initiator_iqn, ibft_strings::len, len, acpi_header::length, ibft_header::length, list_first_entry, list_for_each_entry, memcpy(), netdev, nic, ibft_offset_pair::nic, NULL, offset, offsetof, ibft_control::pair, rc, realloc(), acpi_header::revision, acpi_header::signature, ibft_strings::start, strerror(), ibft_header::structure_id, ibft_offset_pair::target, ibft_header::version, and zalloc().
{ 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; /* Do nothing if no targets exist */ if ( ! targets ) { rc = 0; goto no_targets; } /* 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 ); iscsi = list_first_entry ( &ibft_model.descs, struct iscsi_session, desc.list ); if ( ( rc = ibft_fill_initiator ( initiator, &strings, iscsi->initiator_iqn ) ) != 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: no_targets: free ( strings.data ); return rc; }
struct acpi_model ibft_model __acpi_model |
{ .descs = LIST_HEAD_INIT ( ibft_model.descs ), .complete = ibft_complete, .install = ibft_install, }
iBFT model
aBFT model