2 Implementation for iSCSI Boot Firmware Table publication.
4 Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "IScsiImpl.h"
17 BOOLEAN mIbftInstalled
= FALSE
;
21 Initialize the header of the iSCSI Boot Firmware Table.
23 @param[out] Header The header of the iSCSI Boot Firmware Table.
24 @param[in] OemId The OEM ID.
25 @param[in] OemTableId The OEM table ID for the iBFT.
29 IScsiInitIbfTableHeader (
30 OUT EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Header
,
35 Header
->Signature
= EFI_ACPI_3_0_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE
;
36 Header
->Length
= IBFT_HEAP_OFFSET
;
37 Header
->Revision
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_REVISION
;
40 CopyMem (Header
->OemId
, OemId
, sizeof (Header
->OemId
));
41 CopyMem (&Header
->OemTableId
, OemTableId
, sizeof (UINT64
));
46 Initialize the control section of the iSCSI Boot Firmware Table.
48 @param[in] Table The ACPI table.
52 IScsiInitControlSection (
53 IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Table
56 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*Control
;
59 Control
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*) (Table
+ 1);
61 Control
->Header
.StructureId
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_ID
;
62 Control
->Header
.Version
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_VERSION
;
63 Control
->Header
.Length
= (UINT16
) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
);
66 // If in multipathing mode, enable the Boot Failover Flag.
67 // If in single path mode, disable it. Mix-model is not allowed.
69 // BUGBUG: if Boot Failover Flag is set to 1, the OS installer cannot
70 // find the iSCSI mapped disk. So still keep not set for single path mode.
72 if (mPrivate
->EnableMpio
) {
73 Control
->Header
.Flags
= 0;
74 NumOffset
= 2 * (mPrivate
->MpioCount
- mPrivate
->Krb5MpioCount
);
76 NumOffset
= 2 * mPrivate
->ValidSinglePathCount
;
80 // Each attempt occupies two offsets: one for the NIC section;
81 // the other for the Target section.
85 // Need expand the control section if more than 2 NIC/Target attempts
88 Control
->Header
.Length
= (UINT16
) (Control
->Header
.Length
+ (NumOffset
- 4) * sizeof (UINT16
));
94 Add one item into the heap.
96 @param[in, out] Heap On input, the current address of the heap. On output, the address of
97 the heap after the item is added.
98 @param[in] Data The data to add into the heap.
99 @param[in] Len Length of the Data in byte.
110 // Add one byte for the NULL delimiter.
114 CopyMem (*Heap
, Data
, Len
);
120 Fill the Initiator section of the iSCSI Boot Firmware Table.
122 @param[in] Table The ACPI table.
123 @param[in, out] Heap The heap.
127 IScsiFillInitiatorSection (
128 IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Table
,
132 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*Control
;
133 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
*Initiator
;
135 Control
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*) (Table
+ 1);
138 // Initiator section immediately follows the control section.
140 Initiator
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
*)
141 ((UINT8
*) Control
+ IBFT_ROUNDUP (Control
->Header
.Length
));
143 Control
->InitiatorOffset
= (UINT16
) ((UINTN
) Initiator
- (UINTN
) Table
);
145 Initiator
->Header
.StructureId
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_ID
;
146 Initiator
->Header
.Version
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_VERSION
;
147 Initiator
->Header
.Length
= (UINT16
) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
);
148 Initiator
->Header
.Flags
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_FLAG_BLOCK_VALID
|
149 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_FLAG_BOOT_SELECTED
;
152 // Fill the iSCSI Initiator Name into the heap.
154 IScsiAddHeapItem (Heap
, mPrivate
->InitiatorName
, mPrivate
->InitiatorNameLength
- 1);
156 Initiator
->IScsiNameLength
= (UINT16
) (mPrivate
->InitiatorNameLength
- 1);
157 Initiator
->IScsiNameOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
162 Map the v4 IP address into v6 IP address.
164 @param[in] V4 The v4 IP address.
165 @param[out] V6 The v6 IP address.
170 IN EFI_IPv4_ADDRESS
*V4
,
171 OUT EFI_IPv6_ADDRESS
*V6
176 ZeroMem (V6
, sizeof (EFI_IPv6_ADDRESS
));
181 for (Index
= 0; Index
< 4; Index
++) {
182 V6
->Addr
[12 + Index
] = V4
->Addr
[Index
];
188 Fill the NIC and target sections in iSCSI Boot Firmware Table.
190 @param[in] Table The buffer of the ACPI table.
191 @param[in, out] Heap The heap buffer used to store the variable length
192 parameters such as iSCSI name.
196 IScsiFillNICAndTargetSections (
197 IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Table
,
201 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*Control
;
202 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
*Nic
;
203 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
*Target
;
204 ISCSI_SESSION_CONFIG_NVDATA
*NvData
;
205 ISCSI_CHAP_AUTH_CONFIG_NVDATA
*AuthConfig
;
206 UINT16
*SectionOffset
;
210 ISCSI_ATTEMPT_CONFIG_NVDATA
*Attempt
;
211 ISCSI_NIC_INFO
*NicInfo
;
215 // Get the offset of the first Nic and Target section.
217 Control
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*) (Table
+ 1);
218 Nic
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
*) ((UINTN
) Table
+
219 Control
->InitiatorOffset
+ IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
)));
220 Target
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
*) ((UINTN
) Nic
+
221 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
)));
223 SectionOffset
= &Control
->NIC0Offset
;
228 NET_LIST_FOR_EACH (Entry
, &mPrivate
->AttemptConfigs
) {
231 // First entry should be boot selected entry.
233 Attempt
= IScsiConfigGetAttemptByConfigIndex (mPrivate
->BootSelectedIndex
);
234 if (Attempt
== NULL
) {
236 // First boot selected entry can not be found.
241 ASSERT (Attempt
->SessionConfigData
.Enabled
!= ISCSI_DISABLED
);
244 if (Index
== 1 && Flag
) {
245 Entry
= mPrivate
->AttemptConfigs
.ForwardLink
;
249 Attempt
= NET_LIST_USER_STRUCT (Entry
, ISCSI_ATTEMPT_CONFIG_NVDATA
, Link
);
250 if (Attempt
->AttemptConfigIndex
== mPrivate
->BootSelectedIndex
) {
255 if (Attempt
->SessionConfigData
.Enabled
== ISCSI_DISABLED
) {
260 // Krb5 attempt will not be recorded in iBFT.
262 if (Attempt
->AuthenticationType
== ISCSI_AUTH_TYPE_KRB
) {
267 // If multipath mode is enabled, only the attempts in MPIO will be recorded in iBFT.
269 if (mPrivate
->EnableMpio
&& Attempt
->SessionConfigData
.Enabled
!= ISCSI_ENABLED_FOR_MPIO
) {
274 // Only the valid attempts will be recorded.
276 if (!Attempt
->ValidiBFTPath
) {
280 NvData
= &Attempt
->SessionConfigData
;
281 AuthConfig
= &Attempt
->AuthConfigData
.CHAP
;
284 // Fill the Nic section.
287 Nic
->Header
.StructureId
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_ID
;
288 Nic
->Header
.Version
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_VERSION
;
289 Nic
->Header
.Length
= (UINT16
) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
);
290 Nic
->Header
.Index
= (UINT8
) Index
;
291 Nic
->Header
.Flags
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BLOCK_VALID
|
292 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_GLOBAL
;
295 Nic
->Header
.Flags
|= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BOOT_SELECTED
;
298 if (NvData
->InitiatorInfoFromDhcp
) {
299 Nic
->Origin
= IpPrefixOriginDhcp
;
301 Nic
->Origin
= IpPrefixOriginManual
;
304 if (NvData
->IpMode
== IP_MODE_IP4
|| NvData
->IpMode
== IP_MODE_AUTOCONFIG
) {
306 // Get the subnet mask prefix length.
308 Nic
->SubnetMaskPrefixLength
= IScsiGetSubnetMaskPrefixLength (&NvData
->SubnetMask
);
311 // Map the various v4 addresses into v6 addresses.
313 IScsiMapV4ToV6Addr (&NvData
->LocalIp
.v4
, &Nic
->Ip
);
314 IScsiMapV4ToV6Addr (&NvData
->Gateway
.v4
, &Nic
->Gateway
);
315 IScsiMapV4ToV6Addr (&Attempt
->PrimaryDns
.v4
, &Nic
->PrimaryDns
);
316 IScsiMapV4ToV6Addr (&Attempt
->SecondaryDns
.v4
, &Nic
->SecondaryDns
);
317 IScsiMapV4ToV6Addr (&Attempt
->DhcpServer
.v4
, &Nic
->DhcpServer
);
319 } else if (NvData
->IpMode
== IP_MODE_IP6
|| NvData
->IpMode
== IP_MODE_AUTOCONFIG
) {
321 Nic
->SubnetMaskPrefixLength
= NvData
->PrefixLength
;
322 CopyMem (&Nic
->Ip
, &NvData
->LocalIp
, sizeof (EFI_IPv6_ADDRESS
));
323 CopyMem (&Nic
->Gateway
, &NvData
->Gateway
, sizeof (EFI_IPv6_ADDRESS
));
324 CopyMem (&Nic
->PrimaryDns
, &Attempt
->PrimaryDns
, sizeof (EFI_IPv6_ADDRESS
));
325 CopyMem (&Nic
->SecondaryDns
, &Attempt
->SecondaryDns
, sizeof (EFI_IPv6_ADDRESS
));
326 CopyMem (&Nic
->DhcpServer
, &Attempt
->DhcpServer
, sizeof (EFI_IPv6_ADDRESS
));
333 // Get Nic Info: VLAN tag, Mac address, PCI location.
335 NicInfo
= IScsiGetNicInfoByIndex (Attempt
->NicIndex
);
336 ASSERT (NicInfo
!= NULL
);
338 Nic
->VLanTag
= NicInfo
->VlanId
;
339 CopyMem (Nic
->Mac
, &NicInfo
->PermanentAddress
, sizeof (Nic
->Mac
));
340 Nic
->PciLocation
= (UINT16
) ((NicInfo
->BusNumber
<< 8) |
341 (NicInfo
->DeviceNumber
<< 3) | NicInfo
->FunctionNumber
);
342 *SectionOffset
= (UINT16
) ((UINTN
) Nic
- (UINTN
) Table
);
346 // Fill the Target section.
349 Target
->Header
.StructureId
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_ID
;
350 Target
->Header
.Version
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_VERSION
;
351 Target
->Header
.Length
= (UINT16
) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
);
352 Target
->Header
.Index
= (UINT8
) Index
;
353 Target
->Header
.Flags
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_FLAG_BLOCK_VALID
;
356 Target
->Header
.Flags
|= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_FLAG_BOOT_SELECTED
;
359 Target
->Port
= NvData
->TargetPort
;
361 if (Attempt
->AuthenticationType
== ISCSI_AUTH_TYPE_CHAP
) {
362 if (AuthConfig
->CHAPType
== ISCSI_CHAP_UNI
) {
363 Target
->CHAPType
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_CHAP
;
364 } else if (AuthConfig
->CHAPType
== ISCSI_CHAP_MUTUAL
) {
365 Target
->CHAPType
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_MUTUAL_CHAP
;
367 } else if (Attempt
->AuthenticationType
== ISCSI_AUTH_TYPE_NONE
) {
368 Target
->CHAPType
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_NO_CHAP
;
371 Target
->NicIndex
= (UINT8
) Index
;
373 if (NvData
->IpMode
== IP_MODE_IP4
|| NvData
->IpMode
== IP_MODE_AUTOCONFIG
) {
374 IScsiMapV4ToV6Addr (&NvData
->TargetIp
.v4
, &Target
->Ip
);
375 } else if (NvData
->IpMode
== IP_MODE_IP6
|| NvData
->IpMode
== IP_MODE_AUTOCONFIG
) {
376 CopyMem (&Target
->Ip
, &NvData
->TargetIp
, sizeof (EFI_IPv6_ADDRESS
));
381 CopyMem (Target
->BootLun
, NvData
->BootLun
, sizeof (Target
->BootLun
));
384 // Target iSCSI Name, CHAP name/secret, reverse CHAP name/secret.
386 Length
= (UINT16
) AsciiStrLen (NvData
->TargetName
);
387 IScsiAddHeapItem (Heap
, NvData
->TargetName
, Length
);
389 Target
->IScsiNameLength
= Length
;
390 Target
->IScsiNameOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
392 if (Attempt
->AuthenticationType
== ISCSI_AUTH_TYPE_CHAP
) {
396 Length
= (UINT16
) AsciiStrLen (AuthConfig
->CHAPName
);
397 IScsiAddHeapItem (Heap
, AuthConfig
->CHAPName
, Length
);
398 Target
->CHAPNameLength
= Length
;
399 Target
->CHAPNameOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
404 Length
= (UINT16
) AsciiStrLen (AuthConfig
->CHAPSecret
);
405 IScsiAddHeapItem (Heap
, AuthConfig
->CHAPSecret
, Length
);
406 Target
->CHAPSecretLength
= Length
;
407 Target
->CHAPSecretOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
409 if (Target
->CHAPType
== EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_MUTUAL_CHAP
) {
411 // Reverse CHAP Name.
413 Length
= (UINT16
) AsciiStrLen (AuthConfig
->ReverseCHAPName
);
414 IScsiAddHeapItem (Heap
, AuthConfig
->ReverseCHAPName
, Length
);
415 Target
->ReverseCHAPNameLength
= Length
;
416 Target
->ReverseCHAPNameOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
419 // Reverse CHAP Secret.
421 Length
= (UINT16
) AsciiStrLen (AuthConfig
->ReverseCHAPSecret
);
422 IScsiAddHeapItem (Heap
, AuthConfig
->ReverseCHAPSecret
, Length
);
423 Target
->ReverseCHAPSecretLength
= Length
;
424 Target
->ReverseCHAPSecretOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
428 *SectionOffset
= (UINT16
) ((UINTN
) Target
- (UINTN
) Table
);
432 // Advance to the next NIC/Target pair.
434 Nic
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
*) ((UINTN
) Target
+
435 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
)));
436 Target
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
*) ((UINTN
) Nic
+
437 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
)));
445 Publish and remove the iSCSI Boot Firmware Table according to the iSCSI
455 EFI_ACPI_TABLE_PROTOCOL
*AcpiTableProtocol
;
456 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Table
;
457 EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER
*Rsdp
;
458 EFI_ACPI_DESCRIPTION_HEADER
*Rsdt
;
464 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**) &AcpiTableProtocol
);
465 if (EFI_ERROR (Status
)) {
470 // Find ACPI table RSD_PTR from the system table.
472 for (Index
= 0, Rsdp
= NULL
; Index
< gST
->NumberOfTableEntries
; Index
++) {
473 if (CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), &gEfiAcpi20TableGuid
) ||
474 CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), &gEfiAcpi10TableGuid
) ||
475 CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), &gEfiAcpiTableGuid
)
478 // A match was found.
480 Rsdp
= (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER
*) gST
->ConfigurationTable
[Index
].VendorTable
;
488 Rsdt
= (EFI_ACPI_DESCRIPTION_HEADER
*) (UINTN
) Rsdp
->RsdtAddress
;
491 if (mIbftInstalled
) {
492 Status
= AcpiTableProtocol
->UninstallAcpiTable (
496 if (EFI_ERROR (Status
)) {
499 mIbftInstalled
= FALSE
;
503 // If there is no valid attempt configuration, just return.
505 if ((!mPrivate
->EnableMpio
&& mPrivate
->ValidSinglePathCount
== 0) ||
506 (mPrivate
->EnableMpio
&& mPrivate
->MpioCount
<= mPrivate
->Krb5MpioCount
)) {
511 // Allocate 4k bytes to hold the ACPI table.
513 Table
= AllocateZeroPool (IBFT_MAX_SIZE
);
518 Heap
= (UINT8
*) Table
+ IBFT_HEAP_OFFSET
;
521 // Fill in the various section of the iSCSI Boot Firmware Table.
523 IScsiInitIbfTableHeader (Table
, Rsdt
->OemId
, &Rsdt
->OemTableId
);
524 IScsiInitControlSection (Table
);
525 IScsiFillInitiatorSection (Table
, &Heap
);
526 IScsiFillNICAndTargetSections (Table
, &Heap
);
528 Checksum
= CalculateCheckSum8((UINT8
*)Table
, Table
->Length
);
529 Table
->Checksum
= Checksum
;
532 // Install or update the iBFT table.
534 Status
= AcpiTableProtocol
->InstallAcpiTable (
540 if (EFI_ERROR(Status
)) {
544 mIbftInstalled
= TRUE
;