summaryrefslogtreecommitdiffstats
path: root/src/net
diff options
context:
space:
mode:
authorMichael Brown2017-03-27 17:20:34 +0200
committerMichael Brown2017-03-28 18:12:48 +0200
commit7cfdd769aac76d605aa31146c69ba518b194bea7 (patch)
tree7c09e144792833f81297e6dacf0823733a2a399a /src/net
parent[block] Ignore redundant xfer_window_changed() messages (diff)
downloadipxe-7cfdd769aac76d605aa31146c69ba518b194bea7.tar.gz
ipxe-7cfdd769aac76d605aa31146c69ba518b194bea7.tar.xz
ipxe-7cfdd769aac76d605aa31146c69ba518b194bea7.zip
[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>
Diffstat (limited to 'src/net')
-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
6 files changed, 180 insertions, 120 deletions
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 )