iPXE
ibft.c
Go to the documentation of this file.
00001 /*
00002  * Copyright Fen Systems Ltd. 2007.  Portions of this code are derived
00003  * from IBM Corporation Sample Programs.  Copyright IBM Corporation
00004  * 2004, 2007.  All rights reserved.
00005  *
00006  * Permission is hereby granted, free of charge, to any person
00007  * obtaining a copy of this software and associated documentation
00008  * files (the "Software"), to deal in the Software without
00009  * restriction, including without limitation the rights to use, copy,
00010  * modify, merge, publish, distribute, sublicense, and/or sell copies
00011  * of the Software, and to permit persons to whom the Software is
00012  * furnished to do so, subject to the following conditions:
00013  *
00014  * The above copyright notice and this permission notice shall be
00015  * included in all copies or substantial portions of the Software.
00016  *
00017  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00018  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00019  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00020  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
00021  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
00022  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00023  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00024  * SOFTWARE.
00025  *
00026  */
00027 
00028 FILE_LICENCE ( BSD2 );
00029 
00030 #include <stdint.h>
00031 #include <stdlib.h>
00032 #include <stdio.h>
00033 #include <string.h>
00034 #include <errno.h>
00035 #include <byteswap.h>
00036 #include <ipxe/pci.h>
00037 #include <ipxe/acpi.h>
00038 #include <ipxe/in.h>
00039 #include <ipxe/netdevice.h>
00040 #include <ipxe/ethernet.h>
00041 #include <ipxe/vlan.h>
00042 #include <ipxe/tcpip.h>
00043 #include <ipxe/dhcp.h>
00044 #include <ipxe/iscsi.h>
00045 #include <ipxe/ibft.h>
00046 
00047 /** @file
00048  *
00049  * iSCSI boot firmware table
00050  *
00051  * The information in this file is derived from the document "iSCSI
00052  * Boot Firmware Table (iBFT)" as published by IBM at
00053  *
00054  * ftp://ftp.software.ibm.com/systems/support/system_x_pdf/ibm_iscsi_boot_firmware_table_v1.02.pdf
00055  *
00056  */
00057 
00058 /**
00059  * iSCSI string buffer
00060  *
00061  * This is an internal structure that we use to keep track of the
00062  * allocation of string data.
00063  */
00064 struct ibft_strings {
00065         /** Strings data */
00066         char *data;
00067         /** Starting offset of strings */
00068         size_t start;
00069         /** Total length */
00070         size_t len;
00071 };
00072 
00073 /**
00074  * Align structure within iBFT
00075  *
00076  * @v len               Unaligned length (or offset)
00077  * @ret len             Aligned length (or offset)
00078  */
00079 static inline size_t ibft_align ( size_t len ) {
00080 
00081         return ( ( len + IBFT_ALIGN - 1 ) & ~( IBFT_ALIGN - 1 ) );
00082 }
00083 
00084 /**
00085  * Fill in an IP address field within iBFT
00086  *
00087  * @v ipaddr            IP address field
00088  * @v in                IPv4 address
00089  */
00090 static void ibft_set_ipaddr ( struct ibft_ipaddr *ipaddr, struct in_addr in ) {
00091         memset ( ipaddr, 0, sizeof ( *ipaddr ) );
00092         if ( in.s_addr ) {
00093                 ipaddr->in = in;
00094                 ipaddr->ones = 0xffff;
00095         }
00096 }
00097 
00098 /**
00099  * Fill in an IP address within iBFT from configuration setting
00100  *
00101  * @v settings          Parent settings block, or NULL
00102  * @v ipaddr            IP address field
00103  * @v setting           Configuration setting
00104  * @v count             Maximum number of IP addresses
00105  */
00106 static void ibft_set_ipaddr_setting ( struct settings *settings,
00107                                       struct ibft_ipaddr *ipaddr,
00108                                       const struct setting *setting,
00109                                       unsigned int count ) {
00110         struct in_addr in[count];
00111         unsigned int i;
00112 
00113         fetch_ipv4_array_setting ( settings, setting, in, count );
00114         for ( i = 0 ; i < count ; i++ ) {
00115                 ibft_set_ipaddr ( &ipaddr[i], in[i] );
00116         }
00117 }
00118 
00119 /**
00120  * Read IP address from iBFT (for debugging)
00121  *
00122  * @v strings           iBFT string block descriptor
00123  * @v string            String field
00124  * @ret ipaddr          IP address string
00125  */
00126 static const char * ibft_ipaddr ( struct ibft_ipaddr *ipaddr ) {
00127         return inet_ntoa ( ipaddr->in );
00128 }
00129 
00130 /**
00131  * Allocate a string within iBFT
00132  *
00133  * @v strings           iBFT string block descriptor
00134  * @v string            String field to fill in
00135  * @v len               Length of string to allocate (excluding NUL)
00136  * @ret dest            String destination, or NULL
00137  */
00138 static char * ibft_alloc_string ( struct ibft_strings *strings,
00139                                   struct ibft_string *string, size_t len ) {
00140         size_t new_len;
00141         char *new_data;
00142         char *dest;
00143 
00144         /* Extend string data buffer */
00145         new_len = ( strings->len + len + 1 /* NUL */ );
00146         new_data = realloc ( strings->data, new_len );
00147         if ( ! new_data )
00148                 return NULL;
00149         strings->data = new_data;
00150 
00151         /* Fill in string field */
00152         string->offset = cpu_to_le16 ( strings->start + strings->len );
00153         string->len = cpu_to_le16 ( len );
00154 
00155         /* Zero string */
00156         dest = ( strings->data + strings->len );
00157         memset ( dest, 0, ( len + 1 /* NUL */ ) );
00158 
00159         /* Update allocated length */
00160         strings->len = new_len;
00161 
00162         return dest;
00163 }
00164 
00165 /**
00166  * Fill in a string field within iBFT
00167  *
00168  * @v strings           iBFT string block descriptor
00169  * @v string            String field
00170  * @v data              String to fill in, or NULL
00171  * @ret rc              Return status code
00172  */
00173 static int ibft_set_string ( struct ibft_strings *strings,
00174                              struct ibft_string *string, const char *data ) {
00175         char *dest;
00176 
00177         if ( ! data )
00178                 return 0;
00179 
00180         dest = ibft_alloc_string ( strings, string, strlen ( data ) );
00181         if ( ! dest )
00182                 return -ENOBUFS;
00183         strcpy ( dest, data );
00184 
00185         return 0;
00186 }
00187 
00188 /**
00189  * Fill in a string field within iBFT from configuration setting
00190  *
00191  * @v settings          Parent settings block, or NULL
00192  * @v strings           iBFT string block descriptor
00193  * @v string            String field
00194  * @v setting           Configuration setting
00195  * @ret rc              Return status code
00196  */
00197 static int ibft_set_string_setting ( struct settings *settings,
00198                                      struct ibft_strings *strings,
00199                                      struct ibft_string *string,
00200                                      const struct setting *setting ) {
00201         struct settings *origin;
00202         struct setting fetched;
00203         int len;
00204         char *dest;
00205 
00206         len = fetch_setting ( settings, setting, &origin, &fetched, NULL, 0 );
00207         if ( len < 0 ) {
00208                 string->offset = 0;
00209                 string->len = 0;
00210                 return 0;
00211         }
00212 
00213         dest = ibft_alloc_string ( strings, string, len );
00214         if ( ! dest )
00215                 return -ENOBUFS;
00216         fetch_string_setting ( origin, &fetched, dest, ( len + 1 ));
00217 
00218         return 0;
00219 }
00220 
00221 /**
00222  * Read string from iBFT (for debugging)
00223  *
00224  * @v strings           iBFT string block descriptor
00225  * @v string            String field
00226  * @ret data            String content (or "<empty>")
00227  */
00228 static const char * ibft_string ( struct ibft_strings *strings,
00229                                   struct ibft_string *string ) {
00230         size_t offset = le16_to_cpu ( string->offset );
00231 
00232         return ( offset ? ( strings->data + offset - strings->start ) : NULL );
00233 }
00234 
00235 /**
00236  * Check if network device is required for the iBFT
00237  *
00238  * @v netdev            Network device
00239  * @ret is_required     Network device is required
00240  */
00241 static int ibft_netdev_is_required ( struct net_device *netdev ) {
00242         struct iscsi_session *iscsi;
00243         struct sockaddr_tcpip *st_target;
00244 
00245         list_for_each_entry ( iscsi, &ibft_model.descs, desc.list ) {
00246                 st_target = ( struct sockaddr_tcpip * ) &iscsi->target_sockaddr;
00247                 if ( tcpip_netdev ( st_target ) == netdev )
00248                         return 1;
00249         }
00250 
00251         return 0;
00252 }
00253 
00254 /**
00255  * Fill in NIC portion of iBFT
00256  *
00257  * @v nic               NIC portion of iBFT
00258  * @v strings           iBFT string block descriptor
00259  * @v netdev            Network device
00260  * @ret rc              Return status code
00261  */
00262 static int ibft_fill_nic ( struct ibft_nic *nic,
00263                            struct ibft_strings *strings,
00264                            struct net_device *netdev ) {
00265         struct ll_protocol *ll_protocol = netdev->ll_protocol;
00266         struct in_addr netmask_addr = { 0 };
00267         unsigned int netmask_count = 0;
00268         struct settings *parent = netdev_settings ( netdev );
00269         struct settings *origin;
00270         int rc;
00271 
00272         /* Fill in common header */
00273         nic->header.structure_id = IBFT_STRUCTURE_ID_NIC;
00274         nic->header.version = 1;
00275         nic->header.length = cpu_to_le16 ( sizeof ( *nic ) );
00276         nic->header.flags = ( IBFT_FL_NIC_BLOCK_VALID |
00277                               IBFT_FL_NIC_FIRMWARE_BOOT_SELECTED );
00278         DBG ( "iBFT NIC %d is %s\n", nic->header.index, netdev->name );
00279 
00280         /* Determine origin of IP address */
00281         fetch_setting ( parent, &ip_setting, &origin, NULL, NULL, 0 );
00282         nic->origin = ( ( origin == parent ) ?
00283                         IBFT_NIC_ORIGIN_MANUAL : IBFT_NIC_ORIGIN_DHCP );
00284         DBG ( "iBFT NIC %d origin = %d\n", nic->header.index, nic->origin );
00285 
00286         /* Extract values from configuration settings */
00287         ibft_set_ipaddr_setting ( parent, &nic->ip_address, &ip_setting, 1 );
00288         DBG ( "iBFT NIC %d IP = %s\n",
00289               nic->header.index, ibft_ipaddr ( &nic->ip_address ) );
00290         ibft_set_ipaddr_setting ( parent, &nic->gateway, &gateway_setting, 1 );
00291         DBG ( "iBFT NIC %d gateway = %s\n",
00292               nic->header.index, ibft_ipaddr ( &nic->gateway ) );
00293         ibft_set_ipaddr_setting ( NULL, &nic->dns[0], &dns_setting,
00294                                   ( sizeof ( nic->dns ) /
00295                                     sizeof ( nic->dns[0] ) ) );
00296         ibft_set_ipaddr_setting ( parent, &nic->dhcp, &dhcp_server_setting, 1 );
00297         DBG ( "iBFT NIC %d DNS = %s",
00298               nic->header.index, ibft_ipaddr ( &nic->dns[0] ) );
00299         DBG ( ", %s\n", ibft_ipaddr ( &nic->dns[1] ) );
00300         if ( ( rc = ibft_set_string_setting ( NULL, strings, &nic->hostname,
00301                                               &hostname_setting ) ) != 0 )
00302                 return rc;
00303         DBG ( "iBFT NIC %d hostname = %s\n",
00304               nic->header.index, ibft_string ( strings, &nic->hostname ) );
00305 
00306         /* Derive subnet mask prefix from subnet mask */
00307         fetch_ipv4_setting ( parent, &netmask_setting, &netmask_addr );
00308         while ( netmask_addr.s_addr ) {
00309                 if ( netmask_addr.s_addr & 0x1 )
00310                         netmask_count++;
00311                 netmask_addr.s_addr >>= 1;
00312         }
00313         nic->subnet_mask_prefix = netmask_count;
00314         DBG ( "iBFT NIC %d subnet = /%d\n",
00315               nic->header.index, nic->subnet_mask_prefix );
00316 
00317         /* Extract values from net-device configuration */
00318         nic->vlan = cpu_to_le16 ( vlan_tag ( netdev ) );
00319         DBG ( "iBFT NIC %d VLAN = %02x\n",
00320               nic->header.index, le16_to_cpu ( nic->vlan ) );
00321         if ( ( rc = ll_protocol->eth_addr ( netdev->ll_addr,
00322                                             nic->mac_address ) ) != 0 ) {
00323                 DBG ( "Could not determine %s MAC: %s\n",
00324                       netdev->name, strerror ( rc ) );
00325                 return rc;
00326         }
00327         DBG ( "iBFT NIC %d MAC = %s\n",
00328               nic->header.index, eth_ntoa ( nic->mac_address ) );
00329         nic->pci_bus_dev_func = cpu_to_le16 ( netdev->dev->desc.location );
00330         DBG ( "iBFT NIC %d PCI = %04x\n",
00331               nic->header.index, le16_to_cpu ( nic->pci_bus_dev_func ) );
00332 
00333         return 0;
00334 }
00335 
00336 /**
00337  * Fill in Initiator portion of iBFT
00338  *
00339  * @v initiator         Initiator portion of iBFT
00340  * @v strings           iBFT string block descriptor
00341  * @v initiator_iqn     Initiator IQN
00342  * @ret rc              Return status code
00343  */
00344 static int ibft_fill_initiator ( struct ibft_initiator *initiator,
00345                                  struct ibft_strings *strings,
00346                                  const char *initiator_iqn ) {
00347         int rc;
00348 
00349         /* Fill in common header */
00350         initiator->header.structure_id = IBFT_STRUCTURE_ID_INITIATOR;
00351         initiator->header.version = 1;
00352         initiator->header.length = cpu_to_le16 ( sizeof ( *initiator ) );
00353         initiator->header.flags = ( IBFT_FL_INITIATOR_BLOCK_VALID |
00354                                     IBFT_FL_INITIATOR_FIRMWARE_BOOT_SELECTED );
00355 
00356         /* Fill in initiator name */
00357         if ( ( rc = ibft_set_string ( strings, &initiator->initiator_name,
00358                                       initiator_iqn ) ) != 0 )
00359                 return rc;
00360         DBG ( "iBFT initiator name = %s\n",
00361               ibft_string ( strings, &initiator->initiator_name ) );
00362 
00363         return 0;
00364 }
00365 
00366 /**
00367  * Fill in Target NIC association
00368  *
00369  * @v target            Target portion of iBFT
00370  * @v iscsi             iSCSI session
00371  * @ret rc              Return status code
00372  */
00373 static int ibft_fill_target_nic_association ( struct ibft_target *target,
00374                                               struct iscsi_session *iscsi ) {
00375         struct sockaddr_tcpip *st_target =
00376                 ( struct sockaddr_tcpip * ) &iscsi->target_sockaddr;
00377         struct net_device *associated;
00378         struct net_device *netdev;
00379 
00380         /* Find network device used to reach target */
00381         associated = tcpip_netdev ( st_target );
00382         if ( ! associated ) {
00383                 DBG ( "iBFT target %d has no net device\n",
00384                       target->header.index );
00385                 return -EHOSTUNREACH;
00386         }
00387 
00388         /* Calculate association */
00389         for_each_netdev ( netdev ) {
00390                 if ( netdev == associated ) {
00391                         DBG ( "iBFT target %d uses NIC %d (%s)\n",
00392                               target->header.index, target->nic_association,
00393                               netdev->name );
00394                         return 0;
00395                 }
00396                 if ( ! ibft_netdev_is_required ( netdev ) )
00397                         continue;
00398                 target->nic_association++;
00399         }
00400 
00401         DBG ( "iBFT target %d has impossible NIC %s\n",
00402               target->header.index, netdev->name );
00403         return -EINVAL;
00404 }
00405 
00406 /**
00407  * Fill in Target CHAP portion of iBFT
00408  *
00409  * @v target            Target portion of iBFT
00410  * @v strings           iBFT string block descriptor
00411  * @v iscsi             iSCSI session
00412  * @ret rc              Return status code
00413  */
00414 static int ibft_fill_target_chap ( struct ibft_target *target,
00415                                    struct ibft_strings *strings,
00416                                    struct iscsi_session *iscsi ) {
00417         int rc;
00418 
00419         if ( ! ( iscsi->status & ISCSI_STATUS_AUTH_FORWARD_REQUIRED ) )
00420                 return 0;
00421 
00422         assert ( iscsi->initiator_username );
00423         assert ( iscsi->initiator_password );
00424 
00425         target->chap_type = IBFT_CHAP_ONE_WAY;
00426         if ( ( rc = ibft_set_string ( strings, &target->chap_name,
00427                                       iscsi->initiator_username ) ) != 0 )
00428                 return rc;
00429         DBG ( "iBFT target %d username = %s\n", target->header.index,
00430               ibft_string ( strings, &target->chap_name ) );
00431         if ( ( rc = ibft_set_string ( strings, &target->chap_secret,
00432                                       iscsi->initiator_password ) ) != 0 )
00433                 return rc;
00434         DBG ( "iBFT target %d password = <redacted>\n", target->header.index );
00435 
00436         return 0;
00437 }
00438 
00439 /**
00440  * Fill in Target Reverse CHAP portion of iBFT
00441  *
00442  * @v target            Target portion of iBFT
00443  * @v strings           iBFT string block descriptor
00444  * @v iscsi             iSCSI session
00445  * @ret rc              Return status code
00446  */
00447 static int ibft_fill_target_reverse_chap ( struct ibft_target *target,
00448                                            struct ibft_strings *strings,
00449                                            struct iscsi_session *iscsi ) {
00450         int rc;
00451 
00452         if ( ! ( iscsi->status & ISCSI_STATUS_AUTH_REVERSE_REQUIRED ) )
00453                 return 0;
00454 
00455         assert ( iscsi->initiator_username );
00456         assert ( iscsi->initiator_password );
00457         assert ( iscsi->target_username );
00458         assert ( iscsi->target_password );
00459 
00460         target->chap_type = IBFT_CHAP_MUTUAL;
00461         if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_name,
00462                                       iscsi->target_username ) ) != 0 )
00463                 return rc;
00464         DBG ( "iBFT target %d reverse username = %s\n", target->header.index,
00465               ibft_string ( strings, &target->chap_name ) );
00466         if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_secret,
00467                                       iscsi->target_password ) ) != 0 )
00468                 return rc;
00469         DBG ( "iBFT target %d reverse password = <redacted>\n",
00470               target->header.index );
00471 
00472         return 0;
00473 }
00474 
00475 /**
00476  * Fill in Target portion of iBFT
00477  *
00478  * @v target            Target portion of iBFT
00479  * @v strings           iBFT string block descriptor
00480  * @v iscsi             iSCSI session
00481  * @ret rc              Return status code
00482  */
00483 static int ibft_fill_target ( struct ibft_target *target,
00484                               struct ibft_strings *strings,
00485                               struct iscsi_session *iscsi ) {
00486         struct sockaddr_tcpip *st_target =
00487                 ( struct sockaddr_tcpip * ) &iscsi->target_sockaddr;
00488         struct sockaddr_in *sin_target =
00489                 ( struct sockaddr_in * ) &iscsi->target_sockaddr;
00490         int rc;
00491 
00492         /* Fill in common header */
00493         target->header.structure_id = IBFT_STRUCTURE_ID_TARGET;
00494         target->header.version = 1;
00495         target->header.length = cpu_to_le16 ( sizeof ( *target ) );
00496         target->header.flags = ( IBFT_FL_TARGET_BLOCK_VALID |
00497                                  IBFT_FL_TARGET_FIRMWARE_BOOT_SELECTED );
00498 
00499         /* Fill in Target values */
00500         ibft_set_ipaddr ( &target->ip_address, sin_target->sin_addr );
00501         DBG ( "iBFT target %d IP = %s\n",
00502               target->header.index, ibft_ipaddr ( &target->ip_address ) );
00503         target->socket = cpu_to_le16 ( ntohs ( st_target->st_port ) );
00504         DBG ( "iBFT target %d port = %d\n",
00505               target->header.index, target->socket );
00506         memcpy ( &target->boot_lun, &iscsi->lun, sizeof ( target->boot_lun ) );
00507         DBG ( "iBFT target %d boot LUN = " SCSI_LUN_FORMAT "\n",
00508               target->header.index, SCSI_LUN_DATA ( target->boot_lun ) );
00509         if ( ( rc = ibft_set_string ( strings, &target->target_name,
00510                                       iscsi->target_iqn ) ) != 0 )
00511                 return rc;
00512         DBG ( "iBFT target %d name = %s\n", target->header.index,
00513               ibft_string ( strings, &target->target_name ) );
00514         if ( ( rc = ibft_fill_target_nic_association ( target, iscsi ) ) != 0 )
00515                 return rc;
00516         if ( ( rc = ibft_fill_target_chap ( target, strings, iscsi ) ) != 0 )
00517                 return rc;
00518         if ( ( rc = ibft_fill_target_reverse_chap ( target, strings,
00519                                                     iscsi ) ) != 0 )
00520                 return rc;
00521 
00522         return 0;
00523 }
00524 
00525 /**
00526  * Check if iBFT descriptor is complete
00527  *
00528  * @v desc              ACPI descriptor
00529  * @ret rc              Return status code
00530  */
00531 static int ibft_complete ( struct acpi_descriptor *desc ) {
00532         struct iscsi_session *iscsi =
00533                 container_of ( desc, struct iscsi_session, desc );
00534 
00535         /* Fail if we do not yet have the target address */
00536         if ( ! iscsi->target_sockaddr.sa_family )
00537                 return -EAGAIN;
00538 
00539         return 0;
00540 }
00541 
00542 /**
00543  * Install iBFT
00544  *
00545  * @v install           Installation method
00546  * @ret rc              Return status code
00547  */
00548 static int ibft_install ( int ( * install ) ( struct acpi_header *acpi ) ) {
00549         struct net_device *netdev;
00550         struct iscsi_session *iscsi;
00551         struct ibft_table *table;
00552         struct ibft_initiator *initiator;
00553         struct ibft_nic *nic;
00554         struct ibft_target *target;
00555         struct ibft_strings strings;
00556         struct acpi_header *acpi;
00557         void *data;
00558         unsigned int targets = 0;
00559         unsigned int pairs = 0;
00560         size_t offset = 0;
00561         size_t table_len;
00562         size_t control_len;
00563         size_t initiator_offset;
00564         size_t nic_offset;
00565         size_t target_offset;
00566         size_t strings_offset;
00567         size_t len;
00568         unsigned int i;
00569         int rc;
00570 
00571         /* Calculate table sizes and offsets */
00572         list_for_each_entry ( iscsi, &ibft_model.descs, desc.list )
00573                 targets++;
00574         pairs = ( sizeof ( table->control.pair ) /
00575                   sizeof ( table->control.pair[0] ) );
00576         if ( pairs < targets )
00577                 pairs = targets;
00578         offset = offsetof ( typeof ( *table ), control.pair );
00579         offset += ( pairs * sizeof ( table->control.pair[0] ) );
00580         table_len = offset;
00581         control_len = ( table_len - offsetof ( typeof ( *table ), control ) );
00582         offset = ibft_align ( offset );
00583         initiator_offset = offset;
00584         offset += ibft_align ( sizeof ( *initiator ) );
00585         nic_offset = offset;
00586         offset += ( pairs * ibft_align ( sizeof ( *nic ) ) );
00587         target_offset = offset;
00588         offset += ( pairs * ibft_align ( sizeof ( *target ) ) );
00589         strings_offset = offset;
00590         strings.data = NULL;
00591         strings.start = strings_offset;
00592         strings.len = 0;
00593         len = offset;
00594 
00595         /* Do nothing if no targets exist */
00596         if ( ! targets ) {
00597                 rc = 0;
00598                 goto no_targets;
00599         }
00600 
00601         /* Allocate table */
00602         data = zalloc ( len );
00603         if ( ! data ) {
00604                 rc = -ENOMEM;
00605                 goto err_alloc;
00606         }
00607 
00608         /* Fill in Control block */
00609         table = data;
00610         table->control.header.structure_id = IBFT_STRUCTURE_ID_CONTROL;
00611         table->control.header.version = 1;
00612         table->control.header.length = cpu_to_le16 ( control_len );
00613 
00614         /* Fill in Initiator block */
00615         initiator = ( data + initiator_offset );
00616         table->control.initiator = cpu_to_le16 ( initiator_offset );
00617         iscsi = list_first_entry ( &ibft_model.descs, struct iscsi_session,
00618                                    desc.list );
00619         if ( ( rc = ibft_fill_initiator ( initiator, &strings,
00620                                           iscsi->initiator_iqn ) ) != 0 )
00621                 goto err_initiator;
00622 
00623         /* Fill in NIC blocks */
00624         i = 0;
00625         for_each_netdev ( netdev ) {
00626                 if ( ! ibft_netdev_is_required ( netdev ) )
00627                         continue;
00628                 assert ( i < pairs );
00629                 table->control.pair[i].nic = nic_offset;
00630                 nic = ( data + nic_offset );
00631                 nic->header.index = i;
00632                 if ( ( rc = ibft_fill_nic ( nic, &strings, netdev ) ) != 0 )
00633                         goto err_nic;
00634                 i++;
00635                 nic_offset += ibft_align ( sizeof ( *nic ) );
00636         }
00637 
00638         /* Fill in Target blocks */
00639         i = 0;
00640         list_for_each_entry ( iscsi, &ibft_model.descs, desc.list ) {
00641                 assert ( i < pairs );
00642                 table->control.pair[i].target = target_offset;
00643                 target = ( data + target_offset );
00644                 target->header.index = i;
00645                 if ( ( rc = ibft_fill_target ( target, &strings, iscsi ) ) != 0)
00646                         goto err_target;
00647                 i++;
00648                 target_offset += ibft_align ( sizeof ( *target ) );
00649         }
00650 
00651         /* Reallocate table to include space for strings */
00652         len += strings.len;
00653         acpi = realloc ( data, len );
00654         if ( ! acpi )
00655                 goto err_realloc;
00656         data = NULL;
00657 
00658         /* Fill in ACPI header */
00659         acpi->signature = cpu_to_le32 ( IBFT_SIG );
00660         acpi->length = cpu_to_le32 ( len );
00661         acpi->revision = 1;
00662 
00663         /* Append strings */
00664         memcpy ( ( ( ( void * ) acpi ) + strings_offset ), strings.data,
00665                  strings.len );
00666 
00667         /* Install ACPI table */
00668         if ( ( rc = install ( acpi ) ) != 0 ) {
00669                 DBG ( "iBFT could not install: %s\n", strerror ( rc ) );
00670                 goto err_install;
00671         }
00672 
00673  err_install:
00674         free ( acpi );
00675  err_realloc:
00676  err_target:
00677  err_nic:
00678  err_initiator:
00679         free ( data );
00680  err_alloc:
00681  no_targets:
00682         free ( strings.data );
00683         return rc;
00684 }
00685 
00686 /** iBFT model */
00687 struct acpi_model ibft_model __acpi_model = {
00688         .descs = LIST_HEAD_INIT ( ibft_model.descs ),
00689         .complete = ibft_complete,
00690         .install = ibft_install,
00691 };