2 Miscellaneous routines for iSCSI driver.
4 Copyright (c) 2004 - 2011, 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
);
648 Get the recorded NIC info from global structure by the Index.
650 @param[in] NicIndex The index indicates the position of NIC info.
652 @return Pointer to the NIC info, or NULL if not found.
656 IScsiGetNicInfoByIndex (
661 ISCSI_NIC_INFO
*NicInfo
;
663 NET_LIST_FOR_EACH (Entry
, &mPrivate
->NicInfoList
) {
664 NicInfo
= NET_LIST_USER_STRUCT (Entry
, ISCSI_NIC_INFO
, Link
);
665 if (NicInfo
->NicIndex
== NicIndex
) {
675 Get the NIC's PCI location and return it accroding to the composited
676 format defined in iSCSI Boot Firmware Table.
678 @param[in] Controller The handle of the controller.
679 @param[out] Bus The bus number.
680 @param[out] Device The device number.
681 @param[out] Function The function number.
683 @return The composited representation of the NIC PCI location.
687 IScsiGetNICPciLocation (
688 IN EFI_HANDLE Controller
,
695 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
696 EFI_HANDLE PciIoHandle
;
697 EFI_PCI_IO_PROTOCOL
*PciIo
;
700 Status
= gBS
->HandleProtocol (
702 &gEfiDevicePathProtocolGuid
,
703 (VOID
**) &DevicePath
705 if (EFI_ERROR (Status
)) {
709 Status
= gBS
->LocateDevicePath (
710 &gEfiPciIoProtocolGuid
,
714 if (EFI_ERROR (Status
)) {
718 Status
= gBS
->HandleProtocol (PciIoHandle
, &gEfiPciIoProtocolGuid
, (VOID
**) &PciIo
);
719 if (EFI_ERROR (Status
)) {
723 Status
= PciIo
->GetLocation (PciIo
, &Segment
, Bus
, Device
, Function
);
724 if (EFI_ERROR (Status
)) {
728 return (UINT16
) ((*Bus
<< 8) | (*Device
<< 3) | *Function
);
733 Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
734 buffer, and the size of the buffer. If failure, return NULL.
736 @param[in] Name String part of EFI variable name.
737 @param[in] VendorGuid GUID part of EFI variable name.
738 @param[out] VariableSize Returns the size of the EFI variable that was read.
740 @return Dynamically allocated memory that contains a copy of the EFI variable.
741 @return Caller is responsible freeing the buffer.
742 @retval NULL Variable was not read.
746 IScsiGetVariableAndSize (
748 IN EFI_GUID
*VendorGuid
,
749 OUT UINTN
*VariableSize
759 // Pass in a zero size buffer to find the required buffer size.
762 Status
= gRT
->GetVariable (Name
, VendorGuid
, NULL
, &BufferSize
, Buffer
);
763 if (Status
== EFI_BUFFER_TOO_SMALL
) {
765 // Allocate the buffer to return
767 Buffer
= AllocateZeroPool (BufferSize
);
768 if (Buffer
== NULL
) {
772 // Read variable into the allocated buffer.
774 Status
= gRT
->GetVariable (Name
, VendorGuid
, NULL
, &BufferSize
, Buffer
);
775 if (EFI_ERROR (Status
)) {
780 *VariableSize
= BufferSize
;
786 Create the iSCSI driver data.
788 @param[in] Image The handle of the driver image.
789 @param[in] Controller The handle of the controller.
791 @return The iSCSI driver data created.
792 @retval NULL Other errors as indicated.
796 IScsiCreateDriverData (
798 IN EFI_HANDLE Controller
801 ISCSI_DRIVER_DATA
*Private
;
804 Private
= AllocateZeroPool (sizeof (ISCSI_DRIVER_DATA
));
805 if (Private
== NULL
) {
809 Private
->Signature
= ISCSI_DRIVER_DATA_SIGNATURE
;
810 Private
->Image
= Image
;
811 Private
->Controller
= Controller
;
812 Private
->Session
= NULL
;
815 // Create an event to be signaled when the BS to RT transition is triggerd so
816 // as to abort the iSCSI session.
818 Status
= gBS
->CreateEventEx (
821 IScsiOnExitBootService
,
823 &gEfiEventExitBootServicesGuid
,
824 &Private
->ExitBootServiceEvent
826 if (EFI_ERROR (Status
)) {
831 Private
->ExtScsiPassThruHandle
= NULL
;
832 CopyMem(&Private
->IScsiExtScsiPassThru
, &gIScsiExtScsiPassThruProtocolTemplate
, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL
));
835 // 0 is designated to the TargetId, so use another value for the AdapterId.
837 Private
->ExtScsiPassThruMode
.AdapterId
= 2;
838 Private
->ExtScsiPassThruMode
.Attributes
= EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
| EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
839 Private
->ExtScsiPassThruMode
.IoAlign
= 4;
840 Private
->IScsiExtScsiPassThru
.Mode
= &Private
->ExtScsiPassThruMode
;
847 Clean the iSCSI driver data.
849 @param[in] Private The iSCSI driver data.
853 IScsiCleanDriverData (
854 IN ISCSI_DRIVER_DATA
*Private
859 if (Private
->DevicePath
!= NULL
) {
860 gBS
->UninstallProtocolInterface (
861 Private
->ExtScsiPassThruHandle
,
862 &gEfiDevicePathProtocolGuid
,
866 FreePool (Private
->DevicePath
);
869 if (Private
->ExtScsiPassThruHandle
!= NULL
) {
870 Status
= gBS
->UninstallProtocolInterface (
871 Private
->ExtScsiPassThruHandle
,
872 &gEfiExtScsiPassThruProtocolGuid
,
873 &Private
->IScsiExtScsiPassThru
875 if (!EFI_ERROR (Status
)) {
876 mPrivate
->OneSessionEstablished
= FALSE
;
880 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
887 Get the various configuration data.
889 @param[in] Private The iSCSI driver data.
891 @retval EFI_SUCCESS The configuration data is retrieved.
892 @retval EFI_NOT_FOUND This iSCSI driver is not configured yet.
897 IN ISCSI_DRIVER_DATA
*Private
901 CHAR16 MacString
[ISCSI_MAX_MAC_STRING_LEN
];
903 ISCSI_NIC_INFO
*NicInfo
;
904 ISCSI_ATTEMPT_CONFIG_NVDATA
*AttemptConfigData
;
905 ISCSI_ATTEMPT_CONFIG_NVDATA
*AttemptTmp
;
906 UINT8
*AttemptConfigOrder
;
907 UINTN AttemptConfigOrderSize
;
908 CHAR16 IScsiMode
[64];
912 // There should be at least one attempt configured.
914 AttemptConfigOrder
= IScsiGetVariableAndSize (
917 &AttemptConfigOrderSize
919 if (AttemptConfigOrder
== NULL
|| AttemptConfigOrderSize
== 0) {
920 return EFI_NOT_FOUND
;
924 // Get the iSCSI Initiator Name.
926 mPrivate
->InitiatorNameLength
= ISCSI_NAME_MAX_SIZE
;
927 Status
= gIScsiInitiatorName
.Get (
928 &gIScsiInitiatorName
,
929 &mPrivate
->InitiatorNameLength
,
930 mPrivate
->InitiatorName
932 if (EFI_ERROR (Status
)) {
937 // Get the normal configuration.
939 for (Index
= 0; Index
< AttemptConfigOrderSize
/ sizeof (UINT8
); Index
++) {
942 // Check whether the attempt exists in AttemptConfig.
944 AttemptTmp
= IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder
[Index
]);
945 if (AttemptTmp
!= NULL
&& AttemptTmp
->SessionConfigData
.Enabled
== ISCSI_DISABLED
) {
947 } else if (AttemptTmp
!= NULL
&& AttemptTmp
->SessionConfigData
.Enabled
!= ISCSI_DISABLED
) {
949 // Check the autoconfig path to see whether it should be retried.
951 if (AttemptTmp
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
&&
952 AttemptTmp
->AutoConfigureMode
!= IP_MODE_AUTOCONFIG_SUCCESS
) {
953 if (mPrivate
->Ipv6Flag
&&
954 AttemptTmp
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP6
) {
956 // Autoconfigure for IP6 already attempted but failed. Do not try again.
959 } else if (!mPrivate
->Ipv6Flag
&&
960 AttemptTmp
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP4
) {
962 // Autoconfigure for IP4 already attempted but failed. Do not try again.
967 // Try another approach for this autoconfigure path.
969 AttemptTmp
->AutoConfigureMode
=
970 (UINT8
) (mPrivate
->Ipv6Flag
? IP_MODE_AUTOCONFIG_IP6
: IP_MODE_AUTOCONFIG_IP4
);
971 AttemptTmp
->SessionConfigData
.InitiatorInfoFromDhcp
= TRUE
;
972 AttemptTmp
->SessionConfigData
.TargetInfoFromDhcp
= TRUE
;
973 AttemptTmp
->DhcpSuccess
= FALSE
;
976 // Get some information from the dhcp server.
978 if (!mPrivate
->Ipv6Flag
) {
979 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, AttemptTmp
);
980 if (!EFI_ERROR (Status
)) {
981 AttemptTmp
->DhcpSuccess
= TRUE
;
984 Status
= IScsiDoDhcp6 (Private
->Image
, Private
->Controller
, AttemptTmp
);
985 if (!EFI_ERROR (Status
)) {
986 AttemptTmp
->DhcpSuccess
= TRUE
;
991 // Refresh the state of this attempt to NVR.
993 AsciiStrToUnicodeStr (AttemptTmp
->MacString
, MacString
);
995 mPrivate
->PortString
,
996 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
999 (UINTN
) AttemptTmp
->AttemptConfigIndex
1003 mPrivate
->PortString
,
1004 &gEfiIScsiInitiatorNameProtocolGuid
,
1005 ISCSI_CONFIG_VAR_ATTR
,
1006 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA
),
1012 } else if (AttemptTmp
->SessionConfigData
.InitiatorInfoFromDhcp
&& !AttemptTmp
->ValidPath
) {
1014 // Get DHCP information for already added, but failed, attempt.
1016 AttemptTmp
->DhcpSuccess
= FALSE
;
1017 if (!mPrivate
->Ipv6Flag
&& (AttemptTmp
->SessionConfigData
.IpMode
== IP_MODE_IP4
)) {
1018 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, AttemptTmp
);
1019 if (!EFI_ERROR (Status
)) {
1020 AttemptTmp
->DhcpSuccess
= TRUE
;
1022 } else if (mPrivate
->Ipv6Flag
&& (AttemptTmp
->SessionConfigData
.IpMode
== IP_MODE_IP6
)) {
1023 Status
= IScsiDoDhcp6 (Private
->Image
, Private
->Controller
, AttemptTmp
);
1024 if (!EFI_ERROR (Status
)) {
1025 AttemptTmp
->DhcpSuccess
= TRUE
;
1030 // Refresh the state of this attempt to NVR.
1032 AsciiStrToUnicodeStr (AttemptTmp
->MacString
, MacString
);
1034 mPrivate
->PortString
,
1035 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
1038 (UINTN
) AttemptTmp
->AttemptConfigIndex
1042 mPrivate
->PortString
,
1043 &gEfiIScsiInitiatorNameProtocolGuid
,
1044 ISCSI_CONFIG_VAR_ATTR
,
1045 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA
),
1057 // This attempt does not exist in AttemptConfig. Try to add a new one.
1060 NicInfo
= IScsiGetNicInfoByIndex (mPrivate
->CurrentNic
);
1061 ASSERT (NicInfo
!= NULL
);
1062 IScsiMacAddrToStr (&NicInfo
->PermanentAddress
, NicInfo
->HwAddressSize
, NicInfo
->VlanId
, MacString
);
1064 mPrivate
->PortString
,
1068 (UINTN
) AttemptConfigOrder
[Index
]
1071 AttemptConfigData
= (ISCSI_ATTEMPT_CONFIG_NVDATA
*) GetVariable (
1072 mPrivate
->PortString
,
1073 &gEfiIScsiInitiatorNameProtocolGuid
1076 if (AttemptConfigData
== NULL
) {
1080 ASSERT (AttemptConfigOrder
[Index
] == AttemptConfigData
->AttemptConfigIndex
);
1082 AttemptConfigData
->NicIndex
= NicInfo
->NicIndex
;
1083 AttemptConfigData
->DhcpSuccess
= FALSE
;
1084 AttemptConfigData
->ValidiBFTPath
= (BOOLEAN
) (mPrivate
->EnableMpio
? TRUE
: FALSE
);
1085 AttemptConfigData
->ValidPath
= FALSE
;
1087 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
) {
1088 AttemptConfigData
->SessionConfigData
.InitiatorInfoFromDhcp
= TRUE
;
1089 AttemptConfigData
->SessionConfigData
.TargetInfoFromDhcp
= TRUE
;
1091 AttemptConfigData
->AutoConfigureMode
=
1092 (UINT8
) (mPrivate
->Ipv6Flag
? IP_MODE_AUTOCONFIG_IP6
: IP_MODE_AUTOCONFIG_IP4
);
1096 // Get some information from dhcp server.
1098 if (AttemptConfigData
->SessionConfigData
.Enabled
!= ISCSI_DISABLED
&&
1099 AttemptConfigData
->SessionConfigData
.InitiatorInfoFromDhcp
) {
1101 if (!mPrivate
->Ipv6Flag
&&
1102 (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP4
||
1103 AttemptConfigData
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP4
)) {
1104 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, AttemptConfigData
);
1105 if (!EFI_ERROR (Status
)) {
1106 AttemptConfigData
->DhcpSuccess
= TRUE
;
1108 } else if (mPrivate
->Ipv6Flag
&&
1109 (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP6
||
1110 AttemptConfigData
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP6
)) {
1111 Status
= IScsiDoDhcp6 (Private
->Image
, Private
->Controller
, AttemptConfigData
);
1112 if (!EFI_ERROR (Status
)) {
1113 AttemptConfigData
->DhcpSuccess
= TRUE
;
1118 // Refresh the state of this attempt to NVR.
1120 AsciiStrToUnicodeStr (AttemptConfigData
->MacString
, MacString
);
1122 mPrivate
->PortString
,
1123 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
1126 (UINTN
) AttemptConfigData
->AttemptConfigIndex
1130 mPrivate
->PortString
,
1131 &gEfiIScsiInitiatorNameProtocolGuid
,
1132 ISCSI_CONFIG_VAR_ATTR
,
1133 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA
),
1139 // Update Attempt Help Info.
1142 if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_DISABLED
) {
1143 UnicodeSPrint (IScsiMode
, 64, L
"Disabled");
1144 } else if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED
) {
1145 UnicodeSPrint (IScsiMode
, 64, L
"Enabled");
1146 } else if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED_FOR_MPIO
) {
1147 UnicodeSPrint (IScsiMode
, 64, L
"Enabled for MPIO");
1150 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP4
) {
1151 UnicodeSPrint (IpMode
, 64, L
"IP4");
1152 } else if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP6
) {
1153 UnicodeSPrint (IpMode
, 64, L
"IP6");
1154 } else if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
) {
1155 UnicodeSPrint (IpMode
, 64, L
"Autoconfigure");
1159 mPrivate
->PortString
,
1160 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
1161 L
"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s",
1164 NicInfo
->DeviceNumber
,
1165 NicInfo
->FunctionNumber
,
1170 AttemptConfigData
->AttemptTitleHelpToken
= HiiSetString (
1171 mCallbackInfo
->RegisteredHandle
,
1173 mPrivate
->PortString
,
1176 ASSERT (AttemptConfigData
->AttemptTitleHelpToken
!= 0);
1179 // Record the attempt in global link list.
1181 InsertTailList (&mPrivate
->AttemptConfigs
, &AttemptConfigData
->Link
);
1182 mPrivate
->AttemptCount
++;
1184 if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED_FOR_MPIO
) {
1185 mPrivate
->MpioCount
++;
1186 mPrivate
->EnableMpio
= TRUE
;
1188 if (AttemptConfigData
->AuthenticationType
== ISCSI_AUTH_TYPE_KRB
) {
1189 mPrivate
->Krb5MpioCount
++;
1191 } else if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED
) {
1192 mPrivate
->SinglePathCount
++;
1197 // Reorder the AttemptConfig by the configured order.
1199 for (Index
= 0; Index
< AttemptConfigOrderSize
/ sizeof (UINT8
); Index
++) {
1200 AttemptConfigData
= IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder
[Index
]);
1201 if (AttemptConfigData
== NULL
) {
1205 RemoveEntryList (&AttemptConfigData
->Link
);
1206 InsertTailList (&mPrivate
->AttemptConfigs
, &AttemptConfigData
->Link
);
1210 // Update the Main Form.
1212 IScsiConfigUpdateAttempt ();
1214 FreePool (AttemptConfigOrder
);
1217 // There should be at least one attempt configuration.
1219 if (!mPrivate
->EnableMpio
) {
1220 if (mPrivate
->SinglePathCount
== 0) {
1221 return EFI_NOT_FOUND
;
1223 mPrivate
->ValidSinglePathCount
= mPrivate
->SinglePathCount
;
1231 Get the device path of the iSCSI tcp connection and update it.
1233 @param Session The iSCSI session.
1235 @return The updated device path.
1236 @retval NULL Other errors as indicated.
1239 EFI_DEVICE_PATH_PROTOCOL
*
1240 IScsiGetTcpConnDevicePath (
1241 IN ISCSI_SESSION
*Session
1244 ISCSI_CONNECTION
*Conn
;
1245 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1247 EFI_DEV_PATH
*DPathNode
;
1249 if (Session
->State
!= SESSION_STATE_LOGGED_IN
) {
1253 Conn
= NET_LIST_USER_STRUCT_S (
1254 Session
->Conns
.ForwardLink
,
1257 ISCSI_CONNECTION_SIGNATURE
1260 Status
= gBS
->HandleProtocol (
1262 &gEfiDevicePathProtocolGuid
,
1263 (VOID
**) &DevicePath
1265 if (EFI_ERROR (Status
)) {
1271 DevicePath
= DuplicateDevicePath (DevicePath
);
1272 if (DevicePath
== NULL
) {
1276 DPathNode
= (EFI_DEV_PATH
*) DevicePath
;
1278 while (!IsDevicePathEnd (&DPathNode
->DevPath
)) {
1279 if (DevicePathType (&DPathNode
->DevPath
) == MESSAGING_DEVICE_PATH
) {
1280 if (!Conn
->Ipv6Flag
&& DevicePathSubType (&DPathNode
->DevPath
) == MSG_IPv4_DP
) {
1281 DPathNode
->Ipv4
.LocalPort
= 0;
1282 DPathNode
->Ipv4
.StaticIpAddress
= (BOOLEAN
) !Session
->ConfigData
->SessionConfigData
.InitiatorInfoFromDhcp
;
1284 } else if (Conn
->Ipv6Flag
&& DevicePathSubType (&DPathNode
->DevPath
) == MSG_IPv6_DP
) {
1285 DPathNode
->Ipv6
.LocalPort
= 0;
1286 DPathNode
->Ipv6
.StaticIpAddress
= (BOOLEAN
) !Session
->ConfigData
->SessionConfigData
.InitiatorInfoFromDhcp
;
1291 DPathNode
= (EFI_DEV_PATH
*) NextDevicePathNode (&DPathNode
->DevPath
);
1299 Abort the session when the transition from BS to RT is initiated.
1301 @param[in] Event The event signaled.
1302 @param[in] Context The iSCSI driver data.
1307 IScsiOnExitBootService (
1312 ISCSI_DRIVER_DATA
*Private
;
1314 Private
= (ISCSI_DRIVER_DATA
*) Context
;
1315 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
1317 if (Private
->Session
!= NULL
) {
1318 IScsiSessionAbort (Private
->Session
);