2 Miscellaneous routines for iSCSI driver.
4 Copyright (c) 2004 - 2012, 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 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 IScsiHexString
[] = "0123456789ABCDEFabcdef";
20 Removes (trims) specified leading and trailing characters from a string.
22 @param[in, out] Str Pointer to the null-terminated string to be trimmed.
23 On return, Str will hold the trimmed string.
25 @param[in] CharC Character will be trimmed from str.
42 // Trim off the leading and trailing characters c
44 for (Pointer1
= Str
; (*Pointer1
!= 0) && (*Pointer1
== CharC
); Pointer1
++) {
49 if (Pointer2
== Pointer1
) {
50 while (*Pointer1
!= 0) {
55 while (*Pointer1
!= 0) {
56 *Pointer2
= *Pointer1
;
64 for (Pointer1
= Str
+ StrLen(Str
) - 1; Pointer1
>= Str
&& *Pointer1
== CharC
; Pointer1
--) {
67 if (Pointer1
!= Str
+ StrLen(Str
) - 1) {
73 Calculate the prefix length of the IPv4 subnet mask.
75 @param[in] SubnetMask The IPv4 subnet mask.
77 @return The prefix length of the subnet mask.
78 @retval 0 Other errors as indicated.
82 IScsiGetSubnetMaskPrefixLength (
83 IN EFI_IPv4_ADDRESS
*SubnetMask
90 // The SubnetMask is in network byte order.
92 ReverseMask
= (SubnetMask
->Addr
[0] << 24) | (SubnetMask
->Addr
[1] << 16) | (SubnetMask
->Addr
[2] << 8) | (SubnetMask
->Addr
[3]);
97 ReverseMask
= ~ReverseMask
;
99 if ((ReverseMask
& (ReverseMask
+ 1)) != 0) {
105 while (ReverseMask
!= 0) {
106 ReverseMask
= ReverseMask
>> 1;
110 return (UINT8
) (32 - Len
);
115 Convert the hexadecimal encoded LUN string into the 64-bit LUN.
117 @param[in] Str The hexadecimal encoded LUN string.
118 @param[out] Lun Storage to return the 64-bit LUN.
120 @retval EFI_SUCCESS The 64-bit LUN is stored in Lun.
121 @retval EFI_INVALID_PARAMETER The string is malformatted.
130 UINTN Index
, IndexValue
, IndexNum
, SizeStr
;
137 ZeroMem ((UINT8
*) Value
, sizeof (Value
));
138 SizeStr
= AsciiStrLen (Str
);
142 for (Index
= 0; Index
< SizeStr
; Index
++) {
143 TemStr
[0] = Str
[Index
];
144 TemValue
= (UINT8
) AsciiStrHexToUint64 (TemStr
);
145 if (TemValue
== 0 && TemStr
[0] != '0') {
146 if ((TemStr
[0] != '-') || (IndexNum
== 0)) {
150 return EFI_INVALID_PARAMETER
;
154 if ((TemValue
== 0) && (TemStr
[0] == '-')) {
158 if (++IndexValue
>= 4) {
162 return EFI_INVALID_PARAMETER
;
165 // Restart str index for the next lun value.
171 if (++IndexNum
> 4) {
173 // Each Lun Str can't exceed size 4, because it will be as UINT16 value.
175 return EFI_INVALID_PARAMETER
;
179 // Combine UINT16 value.
181 Value
[IndexValue
] = (UINT16
) ((Value
[IndexValue
] << 4) + TemValue
);
184 for (Index
= 0; Index
<= IndexValue
; Index
++) {
185 *((UINT16
*) &Lun
[Index
* 2]) = HTONS (Value
[Index
]);
192 Convert the 64-bit LUN into the hexadecimal encoded LUN string.
194 @param[in] Lun The 64-bit LUN.
195 @param[out] Str The storage to return the hexadecimal encoded LUN string.
199 IScsiLunToUnicodeStr (
209 for (Index
= 0; Index
< 4; Index
++) {
211 if ((Lun
[2 * Index
] | Lun
[2 * Index
+ 1]) == 0) {
212 StrCpy (TempStr
, L
"0-");
214 TempStr
[0] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
] >> 4];
215 TempStr
[1] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
] & 0x0F];
216 TempStr
[2] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
+ 1] >> 4];
217 TempStr
[3] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
+ 1] & 0x0F];
221 IScsiStrTrim (TempStr
, L
'0');
224 TempStr
+= StrLen (TempStr
);
227 Str
[StrLen (Str
) - 1] = 0;
229 for (Index
= StrLen (Str
) - 1; Index
> 1; Index
= Index
- 2) {
230 if ((Str
[Index
] == L
'0') && (Str
[Index
- 1] == L
'-')) {
239 Convert the formatted IP address into the binary IP address.
241 @param[in] Str The UNICODE string.
242 @param[in] IpMode Indicates whether the IP address is v4 or v6.
243 @param[out] Ip The storage to return the ASCII string.
245 @retval EFI_SUCCESS The binary IP address is returned in Ip.
246 @retval EFI_INVALID_PARAMETER The IP string is malformatted or IpMode is
254 OUT EFI_IP_ADDRESS
*Ip
259 if (IpMode
== IP_MODE_IP4
|| IpMode
== IP_MODE_AUTOCONFIG_IP4
) {
260 return NetLibAsciiStrToIp4 (Str
, &Ip
->v4
);
262 } else if (IpMode
== IP_MODE_IP6
|| IpMode
== IP_MODE_AUTOCONFIG_IP6
) {
263 return NetLibAsciiStrToIp6 (Str
, &Ip
->v6
);
265 } else if (IpMode
== IP_MODE_AUTOCONFIG
) {
266 Status
= NetLibAsciiStrToIp4 (Str
, &Ip
->v4
);
267 if (!EFI_ERROR (Status
)) {
270 return NetLibAsciiStrToIp6 (Str
, &Ip
->v6
);
274 return EFI_INVALID_PARAMETER
;
278 Convert the mac address into a hexadecimal encoded "-" seperated string.
280 @param[in] Mac The mac address.
281 @param[in] Len Length in bytes of the mac address.
282 @param[in] VlanId VLAN ID of the network device.
283 @param[out] Str The storage to return the mac string.
288 IN EFI_MAC_ADDRESS
*Mac
,
297 for (Index
= 0; Index
< Len
; Index
++) {
298 Str
[3 * Index
] = (CHAR16
) IScsiHexString
[(Mac
->Addr
[Index
] >> 4) & 0x0F];
299 Str
[3 * Index
+ 1] = (CHAR16
) IScsiHexString
[Mac
->Addr
[Index
] & 0x0F];
300 Str
[3 * Index
+ 2] = L
':';
303 String
= &Str
[3 * Index
- 1] ;
305 String
+= UnicodeSPrint (String
, 6 * sizeof (CHAR16
), L
"\\%04x", (UINTN
) VlanId
);
312 Convert the binary encoded buffer into a hexadecimal encoded string.
314 @param[in] BinBuffer The buffer containing the binary data.
315 @param[in] BinLength Length of the binary buffer.
316 @param[in, out] HexStr Pointer to the string.
317 @param[in, out] HexLength The length of the string.
319 @retval EFI_SUCCESS The binary data is converted to the hexadecimal string
320 and the length of the string is updated.
321 @retval EFI_BUFFER_TOO_SMALL The string is too small.
322 @retval EFI_INVALID_PARAMETER The IP string is malformatted.
329 IN OUT CHAR8
*HexStr
,
330 IN OUT UINT32
*HexLength
335 if ((HexStr
== NULL
) || (BinBuffer
== NULL
) || (BinLength
== 0)) {
336 return EFI_INVALID_PARAMETER
;
339 if (((*HexLength
) - 3) < BinLength
* 2) {
340 *HexLength
= BinLength
* 2 + 3;
341 return EFI_BUFFER_TOO_SMALL
;
344 *HexLength
= BinLength
* 2 + 3;
346 // Prefix for Hex String.
351 for (Index
= 0; Index
< BinLength
; Index
++) {
352 HexStr
[Index
* 2 + 2] = IScsiHexString
[BinBuffer
[Index
] >> 4];
353 HexStr
[Index
* 2 + 3] = IScsiHexString
[BinBuffer
[Index
] & 0xf];
356 HexStr
[Index
* 2 + 2] = '\0';
363 Convert the hexadecimal string into a binary encoded buffer.
365 @param[in, out] BinBuffer The binary buffer.
366 @param[in, out] BinLength Length of the binary buffer.
367 @param[in] HexStr The hexadecimal string.
369 @retval EFI_SUCCESS The hexadecimal string is converted into a binary
371 @retval EFI_BUFFER_TOO_SMALL The binary buffer is too small to hold the converted data.
376 IN OUT UINT8
*BinBuffer
,
377 IN OUT UINT32
*BinLength
,
386 ZeroMem (TemStr
, sizeof (TemStr
));
389 // Find out how many hex characters the string has.
391 if ((HexStr
[0] == '0') && ((HexStr
[1] == 'x') || (HexStr
[1] == 'X'))) {
395 Length
= AsciiStrLen (HexStr
);
397 for (Index
= 0; Index
< Length
; Index
++) {
398 TemStr
[0] = HexStr
[Index
];
399 Digit
= (UINT8
) AsciiStrHexToUint64 (TemStr
);
400 if (Digit
== 0 && TemStr
[0] != '0') {
406 if ((Index
& 1) == 0) {
407 BinBuffer
[Index
/2] = Digit
;
409 BinBuffer
[Index
/2] = (UINT8
) ((BinBuffer
[Index
/2] << 4) + Digit
);
413 *BinLength
= (UINT32
) ((Index
+ 1)/2);
420 Convert the decimal-constant string or hex-constant string into a numerical value.
422 @param[in] Str String in decimal or hex.
424 @return The numerical value.
432 if ((Str
[0] == '0') && ((Str
[1] == 'x') || (Str
[1] == 'X'))) {
435 return AsciiStrHexToUintn (Str
);
438 return AsciiStrDecimalToUintn (Str
);
443 Generate random numbers.
445 @param[in, out] Rand The buffer to contain random numbers.
446 @param[in] RandLength The length of the Rand buffer.
457 while (RandLength
> 0) {
458 Random
= NET_RANDOM (NetRandomInitSeed ());
459 *Rand
++ = (UINT8
) (Random
);
466 Record the NIC info in global structure.
468 @param[in] Controller The handle of the controller.
470 @retval EFI_SUCCESS The operation is completed.
471 @retval EFI_OUT_OF_RESOURCES Do not have sufficient resources to finish this
477 IN EFI_HANDLE Controller
481 ISCSI_NIC_INFO
*NicInfo
;
483 EFI_MAC_ADDRESS MacAddr
;
488 // Get MAC address of this network device.
490 Status
= NetLibGetMacAddress (Controller
, &MacAddr
, &HwAddressSize
);
491 if (EFI_ERROR (Status
)) {
496 // Get VLAN ID of this network device.
498 VlanId
= NetLibGetVlanId (Controller
);
501 // Check whether the NIC info already exists. Return directly if so.
503 NET_LIST_FOR_EACH (Entry
, &mPrivate
->NicInfoList
) {
504 NicInfo
= NET_LIST_USER_STRUCT (Entry
, ISCSI_NIC_INFO
, Link
);
505 if (NicInfo
->HwAddressSize
== HwAddressSize
&&
506 CompareMem (&NicInfo
->PermanentAddress
, MacAddr
.Addr
, HwAddressSize
) == 0 &&
507 NicInfo
->VlanId
== VlanId
) {
508 mPrivate
->CurrentNic
= NicInfo
->NicIndex
;
512 if (mPrivate
->MaxNic
< NicInfo
->NicIndex
) {
513 mPrivate
->MaxNic
= NicInfo
->NicIndex
;
518 // Record the NIC info in private structure.
520 NicInfo
= AllocateZeroPool (sizeof (ISCSI_NIC_INFO
));
521 if (NicInfo
== NULL
) {
522 return EFI_OUT_OF_RESOURCES
;
525 CopyMem (&NicInfo
->PermanentAddress
, MacAddr
.Addr
, HwAddressSize
);
526 NicInfo
->HwAddressSize
= (UINT32
) HwAddressSize
;
527 NicInfo
->VlanId
= VlanId
;
528 NicInfo
->NicIndex
= (UINT8
) (mPrivate
->MaxNic
+ 1);
529 mPrivate
->MaxNic
= NicInfo
->NicIndex
;
532 // Get the PCI location.
534 IScsiGetNICPciLocation (
537 &NicInfo
->DeviceNumber
,
538 &NicInfo
->FunctionNumber
541 InsertTailList (&mPrivate
->NicInfoList
, &NicInfo
->Link
);
542 mPrivate
->NicCount
++;
544 mPrivate
->CurrentNic
= NicInfo
->NicIndex
;
550 Delete the recorded NIC info from global structure. Also delete corresponding
553 @param[in] Controller The handle of the controller.
555 @retval EFI_SUCCESS The operation is completed.
556 @retval EFI_NOT_FOUND The NIC info to be deleted is not recorded.
561 IN EFI_HANDLE Controller
565 ISCSI_NIC_INFO
*NicInfo
;
567 LIST_ENTRY
*NextEntry
;
568 ISCSI_ATTEMPT_CONFIG_NVDATA
*AttemptConfigData
;
569 ISCSI_NIC_INFO
*ThisNic
;
570 EFI_MAC_ADDRESS MacAddr
;
575 // Get MAC address of this network device.
577 Status
= NetLibGetMacAddress (Controller
, &MacAddr
, &HwAddressSize
);
578 if (EFI_ERROR (Status
)) {
583 // Get VLAN ID of this network device.
585 VlanId
= NetLibGetVlanId (Controller
);
588 // Check whether the NIC information exists.
592 NET_LIST_FOR_EACH (Entry
, &mPrivate
->NicInfoList
) {
593 NicInfo
= NET_LIST_USER_STRUCT (Entry
, ISCSI_NIC_INFO
, Link
);
594 if (NicInfo
->HwAddressSize
== HwAddressSize
&&
595 CompareMem (&NicInfo
->PermanentAddress
, MacAddr
.Addr
, HwAddressSize
) == 0 &&
596 NicInfo
->VlanId
== VlanId
) {
603 if (ThisNic
== NULL
) {
604 return EFI_NOT_FOUND
;
607 mPrivate
->CurrentNic
= ThisNic
->NicIndex
;
609 RemoveEntryList (&ThisNic
->Link
);
611 mPrivate
->NicCount
--;
614 // Remove all attempts related to this NIC.
616 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &mPrivate
->AttemptConfigs
) {
617 AttemptConfigData
= NET_LIST_USER_STRUCT (Entry
, ISCSI_ATTEMPT_CONFIG_NVDATA
, Link
);
618 if (AttemptConfigData
->NicIndex
== mPrivate
->CurrentNic
) {
619 RemoveEntryList (&AttemptConfigData
->Link
);
620 mPrivate
->AttemptCount
--;
622 if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED_FOR_MPIO
&& mPrivate
->MpioCount
> 0) {
623 if (--mPrivate
->MpioCount
== 0) {
624 mPrivate
->EnableMpio
= FALSE
;
627 if (AttemptConfigData
->AuthenticationType
== ISCSI_AUTH_TYPE_KRB
&& mPrivate
->Krb5MpioCount
> 0) {
628 mPrivate
->Krb5MpioCount
--;
631 } else if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED
&& mPrivate
->SinglePathCount
> 0) {
632 mPrivate
->SinglePathCount
--;
634 if (mPrivate
->ValidSinglePathCount
> 0) {
635 mPrivate
->ValidSinglePathCount
--;
639 FreePool (AttemptConfigData
);
644 // Free attempt is created but not saved to system.
646 if (mPrivate
->NewAttempt
!= NULL
) {
647 FreePool (mPrivate
->NewAttempt
);
648 mPrivate
->NewAttempt
= NULL
;
656 Get the recorded NIC info from global structure by the Index.
658 @param[in] NicIndex The index indicates the position of NIC info.
660 @return Pointer to the NIC info, or NULL if not found.
664 IScsiGetNicInfoByIndex (
669 ISCSI_NIC_INFO
*NicInfo
;
671 NET_LIST_FOR_EACH (Entry
, &mPrivate
->NicInfoList
) {
672 NicInfo
= NET_LIST_USER_STRUCT (Entry
, ISCSI_NIC_INFO
, Link
);
673 if (NicInfo
->NicIndex
== NicIndex
) {
683 Get the NIC's PCI location and return it accroding to the composited
684 format defined in iSCSI Boot Firmware Table.
686 @param[in] Controller The handle of the controller.
687 @param[out] Bus The bus number.
688 @param[out] Device The device number.
689 @param[out] Function The function number.
691 @return The composited representation of the NIC PCI location.
695 IScsiGetNICPciLocation (
696 IN EFI_HANDLE Controller
,
703 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
704 EFI_HANDLE PciIoHandle
;
705 EFI_PCI_IO_PROTOCOL
*PciIo
;
708 Status
= gBS
->HandleProtocol (
710 &gEfiDevicePathProtocolGuid
,
711 (VOID
**) &DevicePath
713 if (EFI_ERROR (Status
)) {
717 Status
= gBS
->LocateDevicePath (
718 &gEfiPciIoProtocolGuid
,
722 if (EFI_ERROR (Status
)) {
726 Status
= gBS
->HandleProtocol (PciIoHandle
, &gEfiPciIoProtocolGuid
, (VOID
**) &PciIo
);
727 if (EFI_ERROR (Status
)) {
731 Status
= PciIo
->GetLocation (PciIo
, &Segment
, Bus
, Device
, Function
);
732 if (EFI_ERROR (Status
)) {
736 return (UINT16
) ((*Bus
<< 8) | (*Device
<< 3) | *Function
);
741 Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
742 buffer, and the size of the buffer. If failure, return NULL.
744 @param[in] Name String part of EFI variable name.
745 @param[in] VendorGuid GUID part of EFI variable name.
746 @param[out] VariableSize Returns the size of the EFI variable that was read.
748 @return Dynamically allocated memory that contains a copy of the EFI variable.
749 @return Caller is responsible freeing the buffer.
750 @retval NULL Variable was not read.
754 IScsiGetVariableAndSize (
756 IN EFI_GUID
*VendorGuid
,
757 OUT UINTN
*VariableSize
767 // Pass in a zero size buffer to find the required buffer size.
770 Status
= gRT
->GetVariable (Name
, VendorGuid
, NULL
, &BufferSize
, Buffer
);
771 if (Status
== EFI_BUFFER_TOO_SMALL
) {
773 // Allocate the buffer to return
775 Buffer
= AllocateZeroPool (BufferSize
);
776 if (Buffer
== NULL
) {
780 // Read variable into the allocated buffer.
782 Status
= gRT
->GetVariable (Name
, VendorGuid
, NULL
, &BufferSize
, Buffer
);
783 if (EFI_ERROR (Status
)) {
788 *VariableSize
= BufferSize
;
794 Create the iSCSI driver data.
796 @param[in] Image The handle of the driver image.
797 @param[in] Controller The handle of the controller.
799 @return The iSCSI driver data created.
800 @retval NULL Other errors as indicated.
804 IScsiCreateDriverData (
806 IN EFI_HANDLE Controller
809 ISCSI_DRIVER_DATA
*Private
;
812 Private
= AllocateZeroPool (sizeof (ISCSI_DRIVER_DATA
));
813 if (Private
== NULL
) {
817 Private
->Signature
= ISCSI_DRIVER_DATA_SIGNATURE
;
818 Private
->Image
= Image
;
819 Private
->Controller
= Controller
;
820 Private
->Session
= NULL
;
823 // Create an event to be signaled when the BS to RT transition is triggerd so
824 // as to abort the iSCSI session.
826 Status
= gBS
->CreateEventEx (
829 IScsiOnExitBootService
,
831 &gEfiEventExitBootServicesGuid
,
832 &Private
->ExitBootServiceEvent
834 if (EFI_ERROR (Status
)) {
839 Private
->ExtScsiPassThruHandle
= NULL
;
840 CopyMem(&Private
->IScsiExtScsiPassThru
, &gIScsiExtScsiPassThruProtocolTemplate
, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL
));
843 // 0 is designated to the TargetId, so use another value for the AdapterId.
845 Private
->ExtScsiPassThruMode
.AdapterId
= 2;
846 Private
->ExtScsiPassThruMode
.Attributes
= EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
| EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
847 Private
->ExtScsiPassThruMode
.IoAlign
= 4;
848 Private
->IScsiExtScsiPassThru
.Mode
= &Private
->ExtScsiPassThruMode
;
855 Clean the iSCSI driver data.
857 @param[in] Private The iSCSI driver data.
861 IScsiCleanDriverData (
862 IN ISCSI_DRIVER_DATA
*Private
867 if (Private
->DevicePath
!= NULL
) {
868 gBS
->UninstallProtocolInterface (
869 Private
->ExtScsiPassThruHandle
,
870 &gEfiDevicePathProtocolGuid
,
874 FreePool (Private
->DevicePath
);
877 if (Private
->ExtScsiPassThruHandle
!= NULL
) {
878 Status
= gBS
->UninstallProtocolInterface (
879 Private
->ExtScsiPassThruHandle
,
880 &gEfiExtScsiPassThruProtocolGuid
,
881 &Private
->IScsiExtScsiPassThru
883 if (!EFI_ERROR (Status
)) {
884 mPrivate
->OneSessionEstablished
= FALSE
;
888 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
895 Get the various configuration data.
897 @param[in] Private The iSCSI driver data.
899 @retval EFI_SUCCESS The configuration data is retrieved.
900 @retval EFI_NOT_FOUND This iSCSI driver is not configured yet.
905 IN ISCSI_DRIVER_DATA
*Private
909 CHAR16 MacString
[ISCSI_MAX_MAC_STRING_LEN
];
911 ISCSI_NIC_INFO
*NicInfo
;
912 ISCSI_ATTEMPT_CONFIG_NVDATA
*AttemptConfigData
;
913 ISCSI_ATTEMPT_CONFIG_NVDATA
*AttemptTmp
;
914 UINT8
*AttemptConfigOrder
;
915 UINTN AttemptConfigOrderSize
;
916 CHAR16 IScsiMode
[64];
920 // There should be at least one attempt configured.
922 AttemptConfigOrder
= IScsiGetVariableAndSize (
925 &AttemptConfigOrderSize
927 if (AttemptConfigOrder
== NULL
|| AttemptConfigOrderSize
== 0) {
928 return EFI_NOT_FOUND
;
932 // Get the iSCSI Initiator Name.
934 mPrivate
->InitiatorNameLength
= ISCSI_NAME_MAX_SIZE
;
935 Status
= gIScsiInitiatorName
.Get (
936 &gIScsiInitiatorName
,
937 &mPrivate
->InitiatorNameLength
,
938 mPrivate
->InitiatorName
940 if (EFI_ERROR (Status
)) {
945 // Get the normal configuration.
947 for (Index
= 0; Index
< AttemptConfigOrderSize
/ sizeof (UINT8
); Index
++) {
950 // Check whether the attempt exists in AttemptConfig.
952 AttemptTmp
= IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder
[Index
]);
953 if (AttemptTmp
!= NULL
&& AttemptTmp
->SessionConfigData
.Enabled
== ISCSI_DISABLED
) {
955 } else if (AttemptTmp
!= NULL
&& AttemptTmp
->SessionConfigData
.Enabled
!= ISCSI_DISABLED
) {
957 // Check the autoconfig path to see whether it should be retried.
959 if (AttemptTmp
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
&&
960 AttemptTmp
->AutoConfigureMode
!= IP_MODE_AUTOCONFIG_SUCCESS
) {
961 if (mPrivate
->Ipv6Flag
&&
962 AttemptTmp
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP6
) {
964 // Autoconfigure for IP6 already attempted but failed. Do not try again.
967 } else if (!mPrivate
->Ipv6Flag
&&
968 AttemptTmp
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP4
) {
970 // Autoconfigure for IP4 already attempted but failed. Do not try again.
975 // Try another approach for this autoconfigure path.
977 AttemptTmp
->AutoConfigureMode
=
978 (UINT8
) (mPrivate
->Ipv6Flag
? IP_MODE_AUTOCONFIG_IP6
: IP_MODE_AUTOCONFIG_IP4
);
979 AttemptTmp
->SessionConfigData
.InitiatorInfoFromDhcp
= TRUE
;
980 AttemptTmp
->SessionConfigData
.TargetInfoFromDhcp
= TRUE
;
981 AttemptTmp
->DhcpSuccess
= FALSE
;
984 // Get some information from the dhcp server.
986 if (!mPrivate
->Ipv6Flag
) {
987 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, AttemptTmp
);
988 if (!EFI_ERROR (Status
)) {
989 AttemptTmp
->DhcpSuccess
= TRUE
;
992 Status
= IScsiDoDhcp6 (Private
->Image
, Private
->Controller
, AttemptTmp
);
993 if (!EFI_ERROR (Status
)) {
994 AttemptTmp
->DhcpSuccess
= TRUE
;
999 // Refresh the state of this attempt to NVR.
1001 AsciiStrToUnicodeStr (AttemptTmp
->MacString
, MacString
);
1003 mPrivate
->PortString
,
1004 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
1007 (UINTN
) AttemptTmp
->AttemptConfigIndex
1011 mPrivate
->PortString
,
1012 &gEfiIScsiInitiatorNameProtocolGuid
,
1013 ISCSI_CONFIG_VAR_ATTR
,
1014 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA
),
1020 } else if (AttemptTmp
->SessionConfigData
.InitiatorInfoFromDhcp
&& !AttemptTmp
->ValidPath
) {
1022 // Get DHCP information for already added, but failed, attempt.
1024 AttemptTmp
->DhcpSuccess
= FALSE
;
1025 if (!mPrivate
->Ipv6Flag
&& (AttemptTmp
->SessionConfigData
.IpMode
== IP_MODE_IP4
)) {
1026 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, AttemptTmp
);
1027 if (!EFI_ERROR (Status
)) {
1028 AttemptTmp
->DhcpSuccess
= TRUE
;
1030 } else if (mPrivate
->Ipv6Flag
&& (AttemptTmp
->SessionConfigData
.IpMode
== IP_MODE_IP6
)) {
1031 Status
= IScsiDoDhcp6 (Private
->Image
, Private
->Controller
, AttemptTmp
);
1032 if (!EFI_ERROR (Status
)) {
1033 AttemptTmp
->DhcpSuccess
= TRUE
;
1038 // Refresh the state of this attempt to NVR.
1040 AsciiStrToUnicodeStr (AttemptTmp
->MacString
, MacString
);
1042 mPrivate
->PortString
,
1043 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
1046 (UINTN
) AttemptTmp
->AttemptConfigIndex
1050 mPrivate
->PortString
,
1051 &gEfiIScsiInitiatorNameProtocolGuid
,
1052 ISCSI_CONFIG_VAR_ATTR
,
1053 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA
),
1065 // This attempt does not exist in AttemptConfig. Try to add a new one.
1068 NicInfo
= IScsiGetNicInfoByIndex (mPrivate
->CurrentNic
);
1069 ASSERT (NicInfo
!= NULL
);
1070 IScsiMacAddrToStr (&NicInfo
->PermanentAddress
, NicInfo
->HwAddressSize
, NicInfo
->VlanId
, MacString
);
1072 mPrivate
->PortString
,
1076 (UINTN
) AttemptConfigOrder
[Index
]
1080 mPrivate
->PortString
,
1081 &gEfiIScsiInitiatorNameProtocolGuid
,
1082 (VOID
**)&AttemptConfigData
,
1086 if (AttemptConfigData
== NULL
) {
1090 ASSERT (AttemptConfigOrder
[Index
] == AttemptConfigData
->AttemptConfigIndex
);
1092 AttemptConfigData
->NicIndex
= NicInfo
->NicIndex
;
1093 AttemptConfigData
->DhcpSuccess
= FALSE
;
1094 AttemptConfigData
->ValidiBFTPath
= (BOOLEAN
) (mPrivate
->EnableMpio
? TRUE
: FALSE
);
1095 AttemptConfigData
->ValidPath
= FALSE
;
1097 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
) {
1098 AttemptConfigData
->SessionConfigData
.InitiatorInfoFromDhcp
= TRUE
;
1099 AttemptConfigData
->SessionConfigData
.TargetInfoFromDhcp
= TRUE
;
1101 AttemptConfigData
->AutoConfigureMode
=
1102 (UINT8
) (mPrivate
->Ipv6Flag
? IP_MODE_AUTOCONFIG_IP6
: IP_MODE_AUTOCONFIG_IP4
);
1106 // Get some information from dhcp server.
1108 if (AttemptConfigData
->SessionConfigData
.Enabled
!= ISCSI_DISABLED
&&
1109 AttemptConfigData
->SessionConfigData
.InitiatorInfoFromDhcp
) {
1111 if (!mPrivate
->Ipv6Flag
&&
1112 (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP4
||
1113 AttemptConfigData
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP4
)) {
1114 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, AttemptConfigData
);
1115 if (!EFI_ERROR (Status
)) {
1116 AttemptConfigData
->DhcpSuccess
= TRUE
;
1118 } else if (mPrivate
->Ipv6Flag
&&
1119 (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP6
||
1120 AttemptConfigData
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP6
)) {
1121 Status
= IScsiDoDhcp6 (Private
->Image
, Private
->Controller
, AttemptConfigData
);
1122 if (!EFI_ERROR (Status
)) {
1123 AttemptConfigData
->DhcpSuccess
= TRUE
;
1128 // Refresh the state of this attempt to NVR.
1130 AsciiStrToUnicodeStr (AttemptConfigData
->MacString
, MacString
);
1132 mPrivate
->PortString
,
1133 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
1136 (UINTN
) AttemptConfigData
->AttemptConfigIndex
1140 mPrivate
->PortString
,
1141 &gEfiIScsiInitiatorNameProtocolGuid
,
1142 ISCSI_CONFIG_VAR_ATTR
,
1143 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA
),
1149 // Update Attempt Help Info.
1152 if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_DISABLED
) {
1153 UnicodeSPrint (IScsiMode
, 64, L
"Disabled");
1154 } else if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED
) {
1155 UnicodeSPrint (IScsiMode
, 64, L
"Enabled");
1156 } else if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED_FOR_MPIO
) {
1157 UnicodeSPrint (IScsiMode
, 64, L
"Enabled for MPIO");
1160 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP4
) {
1161 UnicodeSPrint (IpMode
, 64, L
"IP4");
1162 } else if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP6
) {
1163 UnicodeSPrint (IpMode
, 64, L
"IP6");
1164 } else if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
) {
1165 UnicodeSPrint (IpMode
, 64, L
"Autoconfigure");
1169 mPrivate
->PortString
,
1170 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
1171 L
"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s",
1174 NicInfo
->DeviceNumber
,
1175 NicInfo
->FunctionNumber
,
1180 AttemptConfigData
->AttemptTitleHelpToken
= HiiSetString (
1181 mCallbackInfo
->RegisteredHandle
,
1183 mPrivate
->PortString
,
1186 ASSERT (AttemptConfigData
->AttemptTitleHelpToken
!= 0);
1189 // Record the attempt in global link list.
1191 InsertTailList (&mPrivate
->AttemptConfigs
, &AttemptConfigData
->Link
);
1192 mPrivate
->AttemptCount
++;
1194 if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED_FOR_MPIO
) {
1195 mPrivate
->MpioCount
++;
1196 mPrivate
->EnableMpio
= TRUE
;
1198 if (AttemptConfigData
->AuthenticationType
== ISCSI_AUTH_TYPE_KRB
) {
1199 mPrivate
->Krb5MpioCount
++;
1201 } else if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED
) {
1202 mPrivate
->SinglePathCount
++;
1207 // Reorder the AttemptConfig by the configured order.
1209 for (Index
= 0; Index
< AttemptConfigOrderSize
/ sizeof (UINT8
); Index
++) {
1210 AttemptConfigData
= IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder
[Index
]);
1211 if (AttemptConfigData
== NULL
) {
1215 RemoveEntryList (&AttemptConfigData
->Link
);
1216 InsertTailList (&mPrivate
->AttemptConfigs
, &AttemptConfigData
->Link
);
1220 // Update the Main Form.
1222 IScsiConfigUpdateAttempt ();
1224 FreePool (AttemptConfigOrder
);
1227 // There should be at least one attempt configuration.
1229 if (!mPrivate
->EnableMpio
) {
1230 if (mPrivate
->SinglePathCount
== 0) {
1231 return EFI_NOT_FOUND
;
1233 mPrivate
->ValidSinglePathCount
= mPrivate
->SinglePathCount
;
1241 Get the device path of the iSCSI tcp connection and update it.
1243 @param Session The iSCSI session.
1245 @return The updated device path.
1246 @retval NULL Other errors as indicated.
1249 EFI_DEVICE_PATH_PROTOCOL
*
1250 IScsiGetTcpConnDevicePath (
1251 IN ISCSI_SESSION
*Session
1254 ISCSI_CONNECTION
*Conn
;
1255 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1257 EFI_DEV_PATH
*DPathNode
;
1259 if (Session
->State
!= SESSION_STATE_LOGGED_IN
) {
1263 Conn
= NET_LIST_USER_STRUCT_S (
1264 Session
->Conns
.ForwardLink
,
1267 ISCSI_CONNECTION_SIGNATURE
1270 Status
= gBS
->HandleProtocol (
1272 &gEfiDevicePathProtocolGuid
,
1273 (VOID
**) &DevicePath
1275 if (EFI_ERROR (Status
)) {
1281 DevicePath
= DuplicateDevicePath (DevicePath
);
1282 if (DevicePath
== NULL
) {
1286 DPathNode
= (EFI_DEV_PATH
*) DevicePath
;
1288 while (!IsDevicePathEnd (&DPathNode
->DevPath
)) {
1289 if (DevicePathType (&DPathNode
->DevPath
) == MESSAGING_DEVICE_PATH
) {
1290 if (!Conn
->Ipv6Flag
&& DevicePathSubType (&DPathNode
->DevPath
) == MSG_IPv4_DP
) {
1291 DPathNode
->Ipv4
.LocalPort
= 0;
1293 DPathNode
->Ipv4
.StaticIpAddress
=
1294 (BOOLEAN
) (!Session
->ConfigData
->SessionConfigData
.InitiatorInfoFromDhcp
);
1297 &DPathNode
->Ipv4
.GatewayIpAddress
,
1298 &Session
->ConfigData
->SessionConfigData
.Gateway
1302 &DPathNode
->Ipv4
.SubnetMask
,
1303 &Session
->ConfigData
->SessionConfigData
.SubnetMask
1306 } else if (Conn
->Ipv6Flag
&& DevicePathSubType (&DPathNode
->DevPath
) == MSG_IPv6_DP
) {
1307 DPathNode
->Ipv6
.LocalPort
= 0;
1308 DPathNode
->Ipv6
.IpAddressOrigin
= 0;
1309 DPathNode
->Ipv6
.PrefixLength
= IP6_PREFIX_LENGTH
;
1310 ZeroMem (&DPathNode
->Ipv6
.GatewayIpAddress
, sizeof (EFI_IPv6_ADDRESS
));
1315 DPathNode
= (EFI_DEV_PATH
*) NextDevicePathNode (&DPathNode
->DevPath
);
1323 Abort the session when the transition from BS to RT is initiated.
1325 @param[in] Event The event signaled.
1326 @param[in] Context The iSCSI driver data.
1331 IScsiOnExitBootService (
1336 ISCSI_DRIVER_DATA
*Private
;
1338 Private
= (ISCSI_DRIVER_DATA
*) Context
;
1339 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
1341 if (Private
->Session
!= NULL
) {
1342 IScsiSessionAbort (Private
->Session
);