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.
28 IScsiInitIbfTableHeader (
29 OUT EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Header
,
34 ZeroMem (Header
, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
));
36 Header
->Signature
= EFI_ACPI_3_0_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE
;
37 Header
->Length
= IBFT_HEAP_OFFSET
;
38 Header
->Revision
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_REVISION
;
41 CopyMem (Header
->OemId
, OemId
, sizeof (Header
->OemId
));
42 CopyMem (&Header
->OemTableId
, OemTableId
, sizeof (UINT64
));
46 Initialize the control section of the iSCSI Boot Firmware Table.
48 @param[in] Table The ACPI table.
49 @param[in] HandleCount The number of the handles associated with iSCSI sessions, it's
50 equal to the number of iSCSI sessions.
53 IScsiInitControlSection (
54 IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Table
,
58 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*Control
;
61 Control
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*) (Table
+ 1);
63 ZeroMem (Control
, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
));
65 Control
->Header
.StructureId
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_ID
;
66 Control
->Header
.Version
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_VERSION
;
67 Control
->Header
.Length
= (UINT16
) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
);
70 // Each session occupies two offsets, one for the NIC section,
71 // the other for the Target section.
73 NumOffset
= 2 * HandleCount
;
76 // Need expand the control section if more than 2 NIC/Target sections
79 Control
->Header
.Length
= (UINT16
) (Control
->Header
.Length
+ (NumOffset
- 4) * sizeof (UINT16
));
84 Add one item into the heap.
86 @param[in, out] Heap On input, the current address of the heap; On output, the address of
87 the heap after the item is added.
88 @param[in] Data The data to add into the heap.
89 @param[in] Len Length of the Data in byte.
99 // Add one byte for the NULL delimiter.
103 CopyMem (*Heap
, Data
, Len
);
108 Fill the Initiator section of the iSCSI Boot Firmware Table.
110 @param[in] Table The ACPI table.
111 @param[in, out] Heap The heap.
112 @param[in] Handle The handle associated with the iSCSI session.
115 IScsiFillInitiatorSection (
116 IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Table
,
121 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*Control
;
122 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
*Initiator
;
123 ISCSI_DRIVER_DATA
*DriverData
;
124 ISCSI_SESSION
*Session
;
125 ISCSI_PRIVATE_PROTOCOL
*IScsiIdentifier
;
128 Control
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*) (Table
+ 1);
131 // Initiator section immediately follows the control section.
133 Initiator
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
*) ((UINT8
*) Control
+ IBFT_ROUNDUP (Control
->Header
.Length
));
135 Control
->InitiatorOffset
= (UINT16
) ((UINTN
) Initiator
- (UINTN
) Table
);
137 ZeroMem (Initiator
, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
));
139 Initiator
->Header
.StructureId
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_ID
;
140 Initiator
->Header
.Version
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_VERSION
;
141 Initiator
->Header
.Length
= (UINT16
) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
);
142 Initiator
->Header
.Flags
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_FLAG_BLOCK_VALID
| EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_FLAG_BOOT_SELECTED
;
145 // Get the identifier from the handle.
147 Status
= gBS
->HandleProtocol (Handle
, &gEfiCallerIdGuid
, (VOID
**) &IScsiIdentifier
);
148 if (EFI_ERROR (Status
)) {
153 DriverData
= ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier
);
154 Session
= &DriverData
->Session
;
157 // Fill the iSCSI Initiator Name into the heap.
159 IScsiAddHeapItem (Heap
, Session
->InitiatorName
, Session
->InitiatorNameLength
- 1);
161 Initiator
->IScsiNameLength
= (UINT16
) (Session
->InitiatorNameLength
- 1);
162 Initiator
->IScsiNameOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
166 Map the v4 IP address into v6 IP address.
168 @param[in] V4 The v4 IP address.
169 @param[out] V6 The v6 IP address.
173 IN EFI_IPv4_ADDRESS
*V4
,
174 OUT EFI_IPv6_ADDRESS
*V6
179 ZeroMem (V6
, sizeof (EFI_IPv6_ADDRESS
));
184 for (Index
= 0; Index
< 4; Index
++) {
185 V6
->Addr
[12 + Index
] = V4
->Addr
[Index
];
190 Get the NIC's PCI location and return it according to the composited
191 format defined in iSCSI Boot Firmware Table.
193 @param[in] Controller The handle of the controller.
195 @return UINT16 The composited representation of the NIC PCI location.
196 @retval 0 Other errors as indicated.
199 IScsiGetNICPciLocation (
200 IN EFI_HANDLE Controller
204 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
205 EFI_HANDLE PciIoHandle
;
206 EFI_PCI_IO_PROTOCOL
*PciIo
;
212 Status
= gBS
->HandleProtocol (
214 &gEfiDevicePathProtocolGuid
,
217 if (EFI_ERROR (Status
)) {
221 Status
= gBS
->LocateDevicePath (
222 &gEfiPciIoProtocolGuid
,
226 if (EFI_ERROR (Status
)) {
230 Status
= gBS
->HandleProtocol (PciIoHandle
, &gEfiPciIoProtocolGuid
, (VOID
**)&PciIo
);
231 if (EFI_ERROR (Status
)) {
235 Status
= PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
, &Function
);
236 if (EFI_ERROR (Status
)) {
240 return (UINT16
) ((Bus
<< 8) | (Device
<< 3) | Function
);
244 Fill the NIC and target sections in iSCSI Boot Firmware Table.
246 @param[in] Table The buffer of the ACPI table.
247 @param[in, out] Heap The heap buffer used to store the variable length parameters such as iSCSI name.
248 @param[in] HandleCount Count The number of handles having iSCSI private protocol installed.
249 @param[in] Handles The handle buffer.
252 IScsiFillNICAndTargetSections (
253 IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Table
,
255 IN UINTN HandleCount
,
256 IN EFI_HANDLE
*Handles
259 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*Control
;
260 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
*Nic
;
261 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
*Target
;
262 ISCSI_DRIVER_DATA
*DriverData
;
263 ISCSI_SESSION_CONFIG_DATA
*SessionConfigData
;
264 ISCSI_CHAP_AUTH_CONFIG_NVDATA
*AuthConfig
;
265 UINT16
*SectionOffset
;
268 EFI_MAC_ADDRESS MacAddress
;
270 ISCSI_PRIVATE_PROTOCOL
*IScsiIdentifier
;
274 // Get the offset of the first Nic and Target section.
276 Control
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*) (Table
+ 1);
277 Nic
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
*) ((UINTN
) Table
+
278 Control
->InitiatorOffset
+ IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
)));
279 Target
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
*) ((UINTN
) Nic
+
280 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
)));
282 SectionOffset
= &Control
->NIC0Offset
;
284 for (Index
= 0; Index
< HandleCount
; Index
++) {
285 Status
= gBS
->HandleProtocol (Handles
[Index
], &gEfiCallerIdGuid
, (VOID
**)&IScsiIdentifier
);
286 if (EFI_ERROR (Status
)) {
291 DriverData
= ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier
);
292 SessionConfigData
= &DriverData
->Session
.ConfigData
;
293 AuthConfig
= &DriverData
->Session
.AuthData
.AuthConfig
;
296 // Fill the Nic section.
298 ZeroMem (Nic
, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
));
300 Nic
->Header
.StructureId
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_ID
;
301 Nic
->Header
.Version
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_VERSION
;
302 Nic
->Header
.Length
= (UINT16
) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
);
303 Nic
->Header
.Index
= (UINT8
) Index
;
304 Nic
->Header
.Flags
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BLOCK_VALID
|
305 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BOOT_SELECTED
|
306 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_GLOBAL
;
309 // Get the subnet mask prefix length.
311 Nic
->SubnetMaskPrefixLength
= IScsiGetSubnetMaskPrefixLength (&SessionConfigData
->NvData
.SubnetMask
);
313 if (SessionConfigData
->NvData
.InitiatorInfoFromDhcp
) {
314 Nic
->Origin
= IpPrefixOriginDhcp
;
316 Nic
->Origin
= IpPrefixOriginManual
;
319 // Map the various v4 addresses into v6 addresses.
321 IScsiMapV4ToV6Addr (&SessionConfigData
->NvData
.LocalIp
, &Nic
->Ip
);
322 IScsiMapV4ToV6Addr (&SessionConfigData
->NvData
.Gateway
, &Nic
->Gateway
);
323 IScsiMapV4ToV6Addr (&SessionConfigData
->PrimaryDns
, &Nic
->PrimaryDns
);
324 IScsiMapV4ToV6Addr (&SessionConfigData
->SecondaryDns
, &Nic
->SecondaryDns
);
325 IScsiMapV4ToV6Addr (&SessionConfigData
->DhcpServer
, &Nic
->DhcpServer
);
327 Nic
->VLanTag
= NetLibGetVlanId (DriverData
->Controller
);
329 Status
= NetLibGetMacAddress (DriverData
->Controller
, &MacAddress
, &HwAddressSize
);
330 ASSERT (Status
== EFI_SUCCESS
);
331 CopyMem (Nic
->Mac
, MacAddress
.Addr
, sizeof (Nic
->Mac
));
334 // Get the PCI location of the Nic.
336 Nic
->PciLocation
= IScsiGetNICPciLocation (DriverData
->Controller
);
338 *SectionOffset
= (UINT16
) ((UINTN
) Nic
- (UINTN
) Table
);
342 // Fill the Target section.
344 ZeroMem (Target
, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
));
346 Target
->Header
.StructureId
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_ID
;
347 Target
->Header
.Version
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_VERSION
;
348 Target
->Header
.Length
= (UINT16
) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
);
349 Target
->Header
.Index
= (UINT8
) Index
;
350 Target
->Header
.Flags
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_FLAG_BLOCK_VALID
| EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_FLAG_BOOT_SELECTED
;
351 Target
->Port
= SessionConfigData
->NvData
.TargetPort
;
352 Target
->NicIndex
= (UINT8
) Index
;
354 if (AuthConfig
->CHAPType
== ISCSI_CHAP_NONE
) {
355 Target
->CHAPType
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_NO_CHAP
;
356 } if (AuthConfig
->CHAPType
== ISCSI_CHAP_UNI
) {
357 Target
->CHAPType
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_CHAP
;
358 } else if (AuthConfig
->CHAPType
== ISCSI_CHAP_MUTUAL
) {
359 Target
->CHAPType
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_MUTUAL_CHAP
;
362 IScsiMapV4ToV6Addr (&SessionConfigData
->NvData
.TargetIp
, &Target
->Ip
);
363 CopyMem (Target
->BootLun
, SessionConfigData
->NvData
.BootLun
, sizeof (Target
->BootLun
));
366 // Target iSCSI Name, CHAP name/secret, reverse CHAP name/secret.
368 Length
= (UINT16
) AsciiStrLen (SessionConfigData
->NvData
.TargetName
);
369 IScsiAddHeapItem (Heap
, SessionConfigData
->NvData
.TargetName
, Length
);
371 Target
->IScsiNameLength
= Length
;
372 Target
->IScsiNameOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
374 if (Target
->CHAPType
!= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_NO_CHAP
) {
378 Length
= (UINT16
) AsciiStrLen (AuthConfig
->CHAPName
);
379 IScsiAddHeapItem (Heap
, AuthConfig
->CHAPName
, Length
);
380 Target
->CHAPNameLength
= Length
;
381 Target
->CHAPNameOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
386 Length
= (UINT16
) AsciiStrLen (AuthConfig
->CHAPSecret
);
387 IScsiAddHeapItem (Heap
, AuthConfig
->CHAPSecret
, Length
);
388 Target
->CHAPSecretLength
= Length
;
389 Target
->CHAPSecretOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
391 if (Target
->CHAPType
== EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_MUTUAL_CHAP
) {
395 Length
= (UINT16
) AsciiStrLen (AuthConfig
->ReverseCHAPName
);
396 IScsiAddHeapItem (Heap
, AuthConfig
->ReverseCHAPName
, Length
);
397 Target
->ReverseCHAPNameLength
= Length
;
398 Target
->ReverseCHAPNameOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
401 // Reverse CHAP Secret
403 Length
= (UINT16
) AsciiStrLen (AuthConfig
->ReverseCHAPSecret
);
404 IScsiAddHeapItem (Heap
, AuthConfig
->ReverseCHAPSecret
, Length
);
405 Target
->ReverseCHAPSecretLength
= Length
;
406 Target
->ReverseCHAPSecretOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
410 *SectionOffset
= (UINT16
) ((UINTN
) Target
- (UINTN
) Table
);
414 // Advance to the next NIC/Target pair
416 Nic
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
*) ((UINTN
) Target
+
417 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
)));
418 Target
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
*) ((UINTN
) Nic
+
419 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
)));
424 Publish and remove the iSCSI Boot Firmware Table according to the iSCSI
433 EFI_ACPI_TABLE_PROTOCOL
*AcpiTableProtocol
;
434 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Table
;
436 EFI_HANDLE
*HandleBuffer
;
439 EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER
*Rsdp
;
440 EFI_ACPI_DESCRIPTION_HEADER
*Rsdt
;
441 EFI_ACPI_DESCRIPTION_HEADER
*Xsdt
;
446 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**)&AcpiTableProtocol
);
447 if (EFI_ERROR (Status
)) {
453 // Find ACPI table RSD_PTR from system table
455 Status
= EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid
, (VOID
**) &Rsdp
);
456 if (EFI_ERROR (Status
)) {
457 Status
= EfiGetSystemConfigurationTable (&gEfiAcpi10TableGuid
, (VOID
**) &Rsdp
);
460 if (EFI_ERROR (Status
) || (Rsdp
== NULL
)) {
462 } else if (Rsdp
->Revision
>= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION
&& Rsdp
->XsdtAddress
!= 0) {
463 Xsdt
= (EFI_ACPI_DESCRIPTION_HEADER
*) (UINTN
) Rsdp
->XsdtAddress
;
464 } else if (Rsdp
->RsdtAddress
!= 0) {
465 Rsdt
= (EFI_ACPI_DESCRIPTION_HEADER
*) (UINTN
) Rsdp
->RsdtAddress
;
468 if ((Xsdt
== NULL
) && (Rsdt
== NULL
)) {
472 if (mIbftInstalled
) {
473 Status
= AcpiTableProtocol
->UninstallAcpiTable (
477 if (EFI_ERROR (Status
)) {
480 mIbftInstalled
= FALSE
;
484 // Get all iSCSI private protocols.
486 Status
= gBS
->LocateHandleBuffer (
493 if (EFI_ERROR (Status
)) {
497 // Allocate 4k bytes to hold the ACPI table.
499 Table
= AllocateZeroPool (IBFT_MAX_SIZE
);
504 Heap
= (UINT8
*) Table
+ IBFT_HEAP_OFFSET
;
507 // Fill in the various section of the iSCSI Boot Firmware Table.
509 if (Rsdp
->Revision
>= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION
) {
510 IScsiInitIbfTableHeader (Table
, Xsdt
->OemId
, &Xsdt
->OemTableId
);
512 IScsiInitIbfTableHeader (Table
, Rsdt
->OemId
, &Rsdt
->OemTableId
);
515 IScsiInitControlSection (Table
, HandleCount
);
516 IScsiFillInitiatorSection (Table
, &Heap
, HandleBuffer
[0]);
517 IScsiFillNICAndTargetSections (Table
, &Heap
, HandleCount
, HandleBuffer
);
519 Checksum
= CalculateCheckSum8((UINT8
*)Table
, Table
->Length
);
520 Table
->Checksum
= Checksum
;
522 FreePool (HandleBuffer
);
525 // Install or update the iBFT table.
527 Status
= AcpiTableProtocol
->InstallAcpiTable (
533 if (EFI_ERROR(Status
)) {
537 mIbftInstalled
= TRUE
;