1 /*
2 * Copyright Fen Systems Ltd. 2007. Portions of this code are derived
3 * from IBM Corporation Sample Programs. Copyright IBM Corporation
4 * 2004, 2007. All rights reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use, copy,
10 * modify, merge, publish, distribute, sublicense, and/or sell copies
11 * of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 *
26 */
27
28 FILE_LICENCE ( BSD2 );
29
30 #include <stdint.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <byteswap.h>
36 #include <ipxe/pci.h>
37 #include <ipxe/acpi.h>
38 #include <ipxe/in.h>
39 #include <ipxe/netdevice.h>
40 #include <ipxe/ethernet.h>
41 #include <ipxe/vlan.h>
42 #include <ipxe/tcpip.h>
43 #include <ipxe/dhcp.h>
44 #include <ipxe/iscsi.h>
45 #include <ipxe/ibft.h>
46
47 /** @file
48 *
49 * iSCSI boot firmware table
50 *
51 * The information in this file is derived from the document "iSCSI
52 * Boot Firmware Table (iBFT)" as published by IBM at
53 *
54 * ftp://ftp.software.ibm.com/systems/support/system_x_pdf/ibm_iscsi_boot_firmware_table_v1.02.pdf
55 *
56 */
57
58 /**
59 * iSCSI string buffer
60 *
61 * This is an internal structure that we use to keep track of the
62 * allocation of string data.
63 */
64 struct ibft_strings {
65 /** Strings data */
66 char *data;
67 /** Starting offset of strings */
68 size_t start;
69 /** Total length */
70 size_t len;
71 };
72
73 /**
74 * Align structure within iBFT
75 *
76 * @v len Unaligned length (or offset)
77 * @ret len Aligned length (or offset)
78 */
ibft_align(size_t len)79 static inline size_t ibft_align ( size_t len ) {
80
81 return ( ( len + IBFT_ALIGN - 1 ) & ~( IBFT_ALIGN - 1 ) );
82 }
83
84 /**
85 * Fill in an IP address field within iBFT
86 *
87 * @v ipaddr IP address field
88 * @v in IPv4 address
89 */
ibft_set_ipaddr(struct ibft_ipaddr * ipaddr,struct in_addr in)90 static void ibft_set_ipaddr ( struct ibft_ipaddr *ipaddr, struct in_addr in ) {
91 memset ( ipaddr, 0, sizeof ( *ipaddr ) );
92 if ( in.s_addr ) {
93 ipaddr->in = in;
94 ipaddr->ones = 0xffff;
95 }
96 }
97
98 /**
99 * Fill in an IP address within iBFT from configuration setting
100 *
101 * @v settings Parent settings block, or NULL
102 * @v ipaddr IP address field
103 * @v setting Configuration setting
104 * @v count Maximum number of IP addresses
105 */
ibft_set_ipaddr_setting(struct settings * settings,struct ibft_ipaddr * ipaddr,const struct setting * setting,unsigned int count)106 static void ibft_set_ipaddr_setting ( struct settings *settings,
107 struct ibft_ipaddr *ipaddr,
108 const struct setting *setting,
109 unsigned int count ) {
110 struct in_addr in[count];
111 unsigned int i;
112
113 fetch_ipv4_array_setting ( settings, setting, in, count );
114 for ( i = 0 ; i < count ; i++ ) {
115 ibft_set_ipaddr ( &ipaddr[i], in[i] );
116 }
117 }
118
119 /**
120 * Read IP address from iBFT (for debugging)
121 *
122 * @v strings iBFT string block descriptor
123 * @v string String field
124 * @ret ipaddr IP address string
125 */
ibft_ipaddr(struct ibft_ipaddr * ipaddr)126 static const char * ibft_ipaddr ( struct ibft_ipaddr *ipaddr ) {
127 return inet_ntoa ( ipaddr->in );
128 }
129
130 /**
131 * Allocate a string within iBFT
132 *
133 * @v strings iBFT string block descriptor
134 * @v string String field to fill in
135 * @v len Length of string to allocate (excluding NUL)
136 * @ret dest String destination, or NULL
137 */
ibft_alloc_string(struct ibft_strings * strings,struct ibft_string * string,size_t len)138 static char * ibft_alloc_string ( struct ibft_strings *strings,
139 struct ibft_string *string, size_t len ) {
140 size_t new_len;
141 char *new_data;
142 char *dest;
143
144 /* Extend string data buffer */
145 new_len = ( strings->len + len + 1 /* NUL */ );
146 new_data = realloc ( strings->data, new_len );
147 if ( ! new_data )
148 return NULL;
149 strings->data = new_data;
150
151 /* Fill in string field */
152 string->offset = cpu_to_le16 ( strings->start + strings->len );
153 string->len = cpu_to_le16 ( len );
154
155 /* Zero string */
156 dest = ( strings->data + strings->len );
157 memset ( dest, 0, ( len + 1 /* NUL */ ) );
158
159 /* Update allocated length */
160 strings->len = new_len;
161
162 return dest;
163 }
164
165 /**
166 * Fill in a string field within iBFT
167 *
168 * @v strings iBFT string block descriptor
169 * @v string String field
170 * @v data String to fill in, or NULL
171 * @ret rc Return status code
172 */
ibft_set_string(struct ibft_strings * strings,struct ibft_string * string,const char * data)173 static int ibft_set_string ( struct ibft_strings *strings,
174 struct ibft_string *string, const char *data ) {
175 char *dest;
176
177 if ( ! data )
178 return 0;
179
180 dest = ibft_alloc_string ( strings, string, strlen ( data ) );
181 if ( ! dest )
182 return -ENOBUFS;
183 strcpy ( dest, data );
184
185 return 0;
186 }
187
188 /**
189 * Fill in a string field within iBFT from configuration setting
190 *
191 * @v settings Parent settings block, or NULL
192 * @v strings iBFT string block descriptor
193 * @v string String field
194 * @v setting Configuration setting
195 * @ret rc Return status code
196 */
ibft_set_string_setting(struct settings * settings,struct ibft_strings * strings,struct ibft_string * string,const struct setting * setting)197 static int ibft_set_string_setting ( struct settings *settings,
198 struct ibft_strings *strings,
199 struct ibft_string *string,
200 const struct setting *setting ) {
201 struct settings *origin;
202 struct setting fetched;
203 int len;
204 char *dest;
205
206 len = fetch_setting ( settings, setting, &origin, &fetched, NULL, 0 );
207 if ( len < 0 ) {
208 string->offset = 0;
209 string->len = 0;
210 return 0;
211 }
212
213 dest = ibft_alloc_string ( strings, string, len );
214 if ( ! dest )
215 return -ENOBUFS;
216 fetch_string_setting ( origin, &fetched, dest, ( len + 1 ));
217
218 return 0;
219 }
220
221 /**
222 * Read string from iBFT (for debugging)
223 *
224 * @v strings iBFT string block descriptor
225 * @v string String field
226 * @ret data String content (or "<empty>")
227 */
ibft_string(struct ibft_strings * strings,struct ibft_string * string)228 static const char * ibft_string ( struct ibft_strings *strings,
229 struct ibft_string *string ) {
230 size_t offset = le16_to_cpu ( string->offset );
231
232 return ( offset ? ( strings->data + offset - strings->start ) : NULL );
233 }
234
235 /**
236 * Check if network device is required for the iBFT
237 *
238 * @v netdev Network device
239 * @ret is_required Network device is required
240 */
ibft_netdev_is_required(struct net_device * netdev)241 static int ibft_netdev_is_required ( struct net_device *netdev ) {
242 struct iscsi_session *iscsi;
243 struct sockaddr_tcpip *st_target;
244
245 list_for_each_entry ( iscsi, &ibft_model.descs, desc.list ) {
246 st_target = ( struct sockaddr_tcpip * ) &iscsi->target_sockaddr;
247 if ( tcpip_netdev ( st_target ) == netdev )
248 return 1;
249 }
250
251 return 0;
252 }
253
254 /**
255 * Fill in NIC portion of iBFT
256 *
257 * @v nic NIC portion of iBFT
258 * @v strings iBFT string block descriptor
259 * @v netdev Network device
260 * @ret rc Return status code
261 */
ibft_fill_nic(struct ibft_nic * nic,struct ibft_strings * strings,struct net_device * netdev)262 static int ibft_fill_nic ( struct ibft_nic *nic,
263 struct ibft_strings *strings,
264 struct net_device *netdev ) {
265 struct ll_protocol *ll_protocol = netdev->ll_protocol;
266 struct in_addr netmask_addr = { 0 };
267 unsigned int netmask_count = 0;
268 struct settings *parent = netdev_settings ( netdev );
269 struct settings *origin;
270 int rc;
271
272 /* Fill in common header */
273 nic->header.structure_id = IBFT_STRUCTURE_ID_NIC;
274 nic->header.version = 1;
275 nic->header.length = cpu_to_le16 ( sizeof ( *nic ) );
276 nic->header.flags = ( IBFT_FL_NIC_BLOCK_VALID |
277 IBFT_FL_NIC_FIRMWARE_BOOT_SELECTED );
278 DBG ( "iBFT NIC %d is %s\n", nic->header.index, netdev->name );
279
280 /* Determine origin of IP address */
281 fetch_setting ( parent, &ip_setting, &origin, NULL, NULL, 0 );
282 nic->origin = ( ( origin == parent ) ?
283 IBFT_NIC_ORIGIN_MANUAL : IBFT_NIC_ORIGIN_DHCP );
284 DBG ( "iBFT NIC %d origin = %d\n", nic->header.index, nic->origin );
285
286 /* Extract values from configuration settings */
287 ibft_set_ipaddr_setting ( parent, &nic->ip_address, &ip_setting, 1 );
288 DBG ( "iBFT NIC %d IP = %s\n",
289 nic->header.index, ibft_ipaddr ( &nic->ip_address ) );
290 ibft_set_ipaddr_setting ( parent, &nic->gateway, &gateway_setting, 1 );
291 DBG ( "iBFT NIC %d gateway = %s\n",
292 nic->header.index, ibft_ipaddr ( &nic->gateway ) );
293 ibft_set_ipaddr_setting ( NULL, &nic->dns[0], &dns_setting,
294 ( sizeof ( nic->dns ) /
295 sizeof ( nic->dns[0] ) ) );
296 ibft_set_ipaddr_setting ( parent, &nic->dhcp, &dhcp_server_setting, 1 );
297 DBG ( "iBFT NIC %d DNS = %s",
298 nic->header.index, ibft_ipaddr ( &nic->dns[0] ) );
299 DBG ( ", %s\n", ibft_ipaddr ( &nic->dns[1] ) );
300 if ( ( rc = ibft_set_string_setting ( NULL, strings, &nic->hostname,
301 &hostname_setting ) ) != 0 )
302 return rc;
303 DBG ( "iBFT NIC %d hostname = %s\n",
304 nic->header.index, ibft_string ( strings, &nic->hostname ) );
305
306 /* Derive subnet mask prefix from subnet mask */
307 fetch_ipv4_setting ( parent, &netmask_setting, &netmask_addr );
308 while ( netmask_addr.s_addr ) {
309 if ( netmask_addr.s_addr & 0x1 )
310 netmask_count++;
311 netmask_addr.s_addr >>= 1;
312 }
313 nic->subnet_mask_prefix = netmask_count;
314 DBG ( "iBFT NIC %d subnet = /%d\n",
315 nic->header.index, nic->subnet_mask_prefix );
316
317 /* Extract values from net-device configuration */
318 nic->vlan = cpu_to_le16 ( vlan_tag ( netdev ) );
319 DBG ( "iBFT NIC %d VLAN = %02x\n",
320 nic->header.index, le16_to_cpu ( nic->vlan ) );
321 if ( ( rc = ll_protocol->eth_addr ( netdev->ll_addr,
322 nic->mac_address ) ) != 0 ) {
323 DBG ( "Could not determine %s MAC: %s\n",
324 netdev->name, strerror ( rc ) );
325 return rc;
326 }
327 DBG ( "iBFT NIC %d MAC = %s\n",
328 nic->header.index, eth_ntoa ( nic->mac_address ) );
329 nic->pci_bus_dev_func = cpu_to_le16 ( netdev->dev->desc.location );
330 DBG ( "iBFT NIC %d PCI = %04x\n",
331 nic->header.index, le16_to_cpu ( nic->pci_bus_dev_func ) );
332
333 return 0;
334 }
335
336 /**
337 * Fill in Initiator portion of iBFT
338 *
339 * @v initiator Initiator portion of iBFT
340 * @v strings iBFT string block descriptor
341 * @v initiator_iqn Initiator IQN
342 * @ret rc Return status code
343 */
ibft_fill_initiator(struct ibft_initiator * initiator,struct ibft_strings * strings,const char * initiator_iqn)344 static int ibft_fill_initiator ( struct ibft_initiator *initiator,
345 struct ibft_strings *strings,
346 const char *initiator_iqn ) {
347 int rc;
348
349 /* Fill in common header */
350 initiator->header.structure_id = IBFT_STRUCTURE_ID_INITIATOR;
351 initiator->header.version = 1;
352 initiator->header.length = cpu_to_le16 ( sizeof ( *initiator ) );
353 initiator->header.flags = ( IBFT_FL_INITIATOR_BLOCK_VALID |
354 IBFT_FL_INITIATOR_FIRMWARE_BOOT_SELECTED );
355
356 /* Fill in initiator name */
357 if ( ( rc = ibft_set_string ( strings, &initiator->initiator_name,
358 initiator_iqn ) ) != 0 )
359 return rc;
360 DBG ( "iBFT initiator name = %s\n",
361 ibft_string ( strings, &initiator->initiator_name ) );
362
363 return 0;
364 }
365
366 /**
367 * Fill in Target NIC association
368 *
369 * @v target Target portion of iBFT
370 * @v iscsi iSCSI session
371 * @ret rc Return status code
372 */
ibft_fill_target_nic_association(struct ibft_target * target,struct iscsi_session * iscsi)373 static int ibft_fill_target_nic_association ( struct ibft_target *target,
374 struct iscsi_session *iscsi ) {
375 struct sockaddr_tcpip *st_target =
376 ( struct sockaddr_tcpip * ) &iscsi->target_sockaddr;
377 struct net_device *associated;
378 struct net_device *netdev;
379
380 /* Find network device used to reach target */
381 associated = tcpip_netdev ( st_target );
382 if ( ! associated ) {
383 DBG ( "iBFT target %d has no net device\n",
384 target->header.index );
385 return -EHOSTUNREACH;
386 }
387
388 /* Calculate association */
389 for_each_netdev ( netdev ) {
390 if ( netdev == associated ) {
391 DBG ( "iBFT target %d uses NIC %d (%s)\n",
392 target->header.index, target->nic_association,
393 netdev->name );
394 return 0;
395 }
396 if ( ! ibft_netdev_is_required ( netdev ) )
397 continue;
398 target->nic_association++;
399 }
400
401 DBG ( "iBFT target %d has impossible NIC %s\n",
402 target->header.index, netdev->name );
403 return -EINVAL;
404 }
405
406 /**
407 * Fill in Target CHAP portion of iBFT
408 *
409 * @v target Target portion of iBFT
410 * @v strings iBFT string block descriptor
411 * @v iscsi iSCSI session
412 * @ret rc Return status code
413 */
ibft_fill_target_chap(struct ibft_target * target,struct ibft_strings * strings,struct iscsi_session * iscsi)414 static int ibft_fill_target_chap ( struct ibft_target *target,
415 struct ibft_strings *strings,
416 struct iscsi_session *iscsi ) {
417 int rc;
418
419 if ( ! ( iscsi->status & ISCSI_STATUS_AUTH_FORWARD_REQUIRED ) )
420 return 0;
421
422 assert ( iscsi->initiator_username );
423 assert ( iscsi->initiator_password );
424
425 target->chap_type = IBFT_CHAP_ONE_WAY;
426 if ( ( rc = ibft_set_string ( strings, &target->chap_name,
427 iscsi->initiator_username ) ) != 0 )
428 return rc;
429 DBG ( "iBFT target %d username = %s\n", target->header.index,
430 ibft_string ( strings, &target->chap_name ) );
431 if ( ( rc = ibft_set_string ( strings, &target->chap_secret,
432 iscsi->initiator_password ) ) != 0 )
433 return rc;
434 DBG ( "iBFT target %d password = <redacted>\n", target->header.index );
435
436 return 0;
437 }
438
439 /**
440 * Fill in Target Reverse CHAP portion of iBFT
441 *
442 * @v target Target portion of iBFT
443 * @v strings iBFT string block descriptor
444 * @v iscsi iSCSI session
445 * @ret rc Return status code
446 */
ibft_fill_target_reverse_chap(struct ibft_target * target,struct ibft_strings * strings,struct iscsi_session * iscsi)447 static int ibft_fill_target_reverse_chap ( struct ibft_target *target,
448 struct ibft_strings *strings,
449 struct iscsi_session *iscsi ) {
450 int rc;
451
452 if ( ! ( iscsi->status & ISCSI_STATUS_AUTH_REVERSE_REQUIRED ) )
453 return 0;
454
455 assert ( iscsi->initiator_username );
456 assert ( iscsi->initiator_password );
457 assert ( iscsi->target_username );
458 assert ( iscsi->target_password );
459
460 target->chap_type = IBFT_CHAP_MUTUAL;
461 if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_name,
462 iscsi->target_username ) ) != 0 )
463 return rc;
464 DBG ( "iBFT target %d reverse username = %s\n", target->header.index,
465 ibft_string ( strings, &target->chap_name ) );
466 if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_secret,
467 iscsi->target_password ) ) != 0 )
468 return rc;
469 DBG ( "iBFT target %d reverse password = <redacted>\n",
470 target->header.index );
471
472 return 0;
473 }
474
475 /**
476 * Fill in Target portion of iBFT
477 *
478 * @v target Target portion of iBFT
479 * @v strings iBFT string block descriptor
480 * @v iscsi iSCSI session
481 * @ret rc Return status code
482 */
ibft_fill_target(struct ibft_target * target,struct ibft_strings * strings,struct iscsi_session * iscsi)483 static int ibft_fill_target ( struct ibft_target *target,
484 struct ibft_strings *strings,
485 struct iscsi_session *iscsi ) {
486 struct sockaddr_tcpip *st_target =
487 ( struct sockaddr_tcpip * ) &iscsi->target_sockaddr;
488 struct sockaddr_in *sin_target =
489 ( struct sockaddr_in * ) &iscsi->target_sockaddr;
490 int rc;
491
492 /* Fill in common header */
493 target->header.structure_id = IBFT_STRUCTURE_ID_TARGET;
494 target->header.version = 1;
495 target->header.length = cpu_to_le16 ( sizeof ( *target ) );
496 target->header.flags = ( IBFT_FL_TARGET_BLOCK_VALID |
497 IBFT_FL_TARGET_FIRMWARE_BOOT_SELECTED );
498
499 /* Fill in Target values */
500 ibft_set_ipaddr ( &target->ip_address, sin_target->sin_addr );
501 DBG ( "iBFT target %d IP = %s\n",
502 target->header.index, ibft_ipaddr ( &target->ip_address ) );
503 target->socket = cpu_to_le16 ( ntohs ( st_target->st_port ) );
504 DBG ( "iBFT target %d port = %d\n",
505 target->header.index, target->socket );
506 memcpy ( &target->boot_lun, &iscsi->lun, sizeof ( target->boot_lun ) );
507 DBG ( "iBFT target %d boot LUN = " SCSI_LUN_FORMAT "\n",
508 target->header.index, SCSI_LUN_DATA ( target->boot_lun ) );
509 if ( ( rc = ibft_set_string ( strings, &target->target_name,
510 iscsi->target_iqn ) ) != 0 )
511 return rc;
512 DBG ( "iBFT target %d name = %s\n", target->header.index,
513 ibft_string ( strings, &target->target_name ) );
514 if ( ( rc = ibft_fill_target_nic_association ( target, iscsi ) ) != 0 )
515 return rc;
516 if ( ( rc = ibft_fill_target_chap ( target, strings, iscsi ) ) != 0 )
517 return rc;
518 if ( ( rc = ibft_fill_target_reverse_chap ( target, strings,
519 iscsi ) ) != 0 )
520 return rc;
521
522 return 0;
523 }
524
525 /**
526 * Check if iBFT descriptor is complete
527 *
528 * @v desc ACPI descriptor
529 * @ret rc Return status code
530 */
ibft_complete(struct acpi_descriptor * desc)531 static int ibft_complete ( struct acpi_descriptor *desc ) {
532 struct iscsi_session *iscsi =
533 container_of ( desc, struct iscsi_session, desc );
534
535 /* Fail if we do not yet have the target address */
536 if ( ! iscsi->target_sockaddr.sa_family )
537 return -EAGAIN;
538
539 return 0;
540 }
541
542 /**
543 * Install iBFT
544 *
545 * @v install Installation method
546 * @ret rc Return status code
547 */
ibft_install(int (* install)(struct acpi_header * acpi))548 static int ibft_install ( int ( * install ) ( struct acpi_header *acpi ) ) {
549 struct net_device *netdev;
550 struct iscsi_session *iscsi;
551 struct ibft_table *table;
552 struct ibft_initiator *initiator;
553 struct ibft_nic *nic;
554 struct ibft_target *target;
555 struct ibft_strings strings;
556 struct acpi_header *acpi;
557 void *data;
558 unsigned int targets = 0;
559 unsigned int pairs = 0;
560 size_t offset = 0;
561 size_t table_len;
562 size_t control_len;
563 size_t initiator_offset;
564 size_t nic_offset;
565 size_t target_offset;
566 size_t strings_offset;
567 size_t len;
568 unsigned int i;
569 int rc;
570
571 /* Calculate table sizes and offsets */
572 list_for_each_entry ( iscsi, &ibft_model.descs, desc.list )
573 targets++;
574 pairs = ( sizeof ( table->control.pair ) /
575 sizeof ( table->control.pair[0] ) );
576 if ( pairs < targets )
577 pairs = targets;
578 offset = offsetof ( typeof ( *table ), control.pair );
579 offset += ( pairs * sizeof ( table->control.pair[0] ) );
580 table_len = offset;
581 control_len = ( table_len - offsetof ( typeof ( *table ), control ) );
582 offset = ibft_align ( offset );
583 initiator_offset = offset;
584 offset += ibft_align ( sizeof ( *initiator ) );
585 nic_offset = offset;
586 offset += ( pairs * ibft_align ( sizeof ( *nic ) ) );
587 target_offset = offset;
588 offset += ( pairs * ibft_align ( sizeof ( *target ) ) );
589 strings_offset = offset;
590 strings.data = NULL;
591 strings.start = strings_offset;
592 strings.len = 0;
593 len = offset;
594
595 /* Do nothing if no targets exist */
596 if ( ! targets ) {
597 rc = 0;
598 goto no_targets;
599 }
600
601 /* Allocate table */
602 data = zalloc ( len );
603 if ( ! data ) {
604 rc = -ENOMEM;
605 goto err_alloc;
606 }
607
608 /* Fill in Control block */
609 table = data;
610 table->control.header.structure_id = IBFT_STRUCTURE_ID_CONTROL;
611 table->control.header.version = 1;
612 table->control.header.length = cpu_to_le16 ( control_len );
613
614 /* Fill in Initiator block */
615 initiator = ( data + initiator_offset );
616 table->control.initiator = cpu_to_le16 ( initiator_offset );
617 iscsi = list_first_entry ( &ibft_model.descs, struct iscsi_session,
618 desc.list );
619 if ( ( rc = ibft_fill_initiator ( initiator, &strings,
620 iscsi->initiator_iqn ) ) != 0 )
621 goto err_initiator;
622
623 /* Fill in NIC blocks */
624 i = 0;
625 for_each_netdev ( netdev ) {
626 if ( ! ibft_netdev_is_required ( netdev ) )
627 continue;
628 assert ( i < pairs );
629 table->control.pair[i].nic = nic_offset;
630 nic = ( data + nic_offset );
631 nic->header.index = i;
632 if ( ( rc = ibft_fill_nic ( nic, &strings, netdev ) ) != 0 )
633 goto err_nic;
634 i++;
635 nic_offset += ibft_align ( sizeof ( *nic ) );
636 }
637
638 /* Fill in Target blocks */
639 i = 0;
640 list_for_each_entry ( iscsi, &ibft_model.descs, desc.list ) {
641 assert ( i < pairs );
642 table->control.pair[i].target = target_offset;
643 target = ( data + target_offset );
644 target->header.index = i;
645 if ( ( rc = ibft_fill_target ( target, &strings, iscsi ) ) != 0)
646 goto err_target;
647 i++;
648 target_offset += ibft_align ( sizeof ( *target ) );
649 }
650
651 /* Reallocate table to include space for strings */
652 len += strings.len;
653 acpi = realloc ( data, len );
654 if ( ! acpi )
655 goto err_realloc;
656 data = NULL;
657
658 /* Fill in ACPI header */
659 acpi->signature = cpu_to_le32 ( IBFT_SIG );
660 acpi->length = cpu_to_le32 ( len );
661 acpi->revision = 1;
662
663 /* Append strings */
664 memcpy ( ( ( ( void * ) acpi ) + strings_offset ), strings.data,
665 strings.len );
666
667 /* Install ACPI table */
668 if ( ( rc = install ( acpi ) ) != 0 ) {
669 DBG ( "iBFT could not install: %s\n", strerror ( rc ) );
670 goto err_install;
671 }
672
673 err_install:
674 free ( acpi );
675 err_realloc:
676 err_target:
677 err_nic:
678 err_initiator:
679 free ( data );
680 err_alloc:
681 no_targets:
682 free ( strings.data );
683 return rc;
684 }
685
686 /** iBFT model */
687 struct acpi_model ibft_model __acpi_model = {
688 .descs = LIST_HEAD_INIT ( ibft_model.descs ),
689 .complete = ibft_complete,
690 .install = ibft_install,
691 };
692