2 Miscellaneous routines for iSCSI driver.
4 Copyright (c) 2004 - 2014, 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 CopyMem (TempStr
, L
"0-", sizeof (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 // Remove the last '-'
229 Str
[StrLen (Str
) - 1] = 0;
231 for (Index
= StrLen (Str
) - 1; Index
> 1; Index
= Index
- 2) {
232 if ((Str
[Index
] == L
'0') && (Str
[Index
- 1] == L
'-')) {
241 Convert the formatted IP address into the binary IP address.
243 @param[in] Str The UNICODE string.
244 @param[in] IpMode Indicates whether the IP address is v4 or v6.
245 @param[out] Ip The storage to return the ASCII string.
247 @retval EFI_SUCCESS The binary IP address is returned in Ip.
248 @retval EFI_INVALID_PARAMETER The IP string is malformatted or IpMode is
256 OUT EFI_IP_ADDRESS
*Ip
261 if (IpMode
== IP_MODE_IP4
|| IpMode
== IP_MODE_AUTOCONFIG_IP4
) {
262 return NetLibAsciiStrToIp4 (Str
, &Ip
->v4
);
264 } else if (IpMode
== IP_MODE_IP6
|| IpMode
== IP_MODE_AUTOCONFIG_IP6
) {
265 return NetLibAsciiStrToIp6 (Str
, &Ip
->v6
);
267 } else if (IpMode
== IP_MODE_AUTOCONFIG
) {
268 Status
= NetLibAsciiStrToIp4 (Str
, &Ip
->v4
);
269 if (!EFI_ERROR (Status
)) {
272 return NetLibAsciiStrToIp6 (Str
, &Ip
->v6
);
276 return EFI_INVALID_PARAMETER
;
280 Convert the mac address into a hexadecimal encoded "-" seperated string.
282 @param[in] Mac The mac address.
283 @param[in] Len Length in bytes of the mac address.
284 @param[in] VlanId VLAN ID of the network device.
285 @param[out] Str The storage to return the mac string.
290 IN EFI_MAC_ADDRESS
*Mac
,
299 for (Index
= 0; Index
< Len
; Index
++) {
300 Str
[3 * Index
] = (CHAR16
) IScsiHexString
[(Mac
->Addr
[Index
] >> 4) & 0x0F];
301 Str
[3 * Index
+ 1] = (CHAR16
) IScsiHexString
[Mac
->Addr
[Index
] & 0x0F];
302 Str
[3 * Index
+ 2] = L
':';
305 String
= &Str
[3 * Index
- 1] ;
307 String
+= UnicodeSPrint (String
, 6 * sizeof (CHAR16
), L
"\\%04x", (UINTN
) VlanId
);
314 Convert the binary encoded buffer into a hexadecimal encoded string.
316 @param[in] BinBuffer The buffer containing the binary data.
317 @param[in] BinLength Length of the binary buffer.
318 @param[in, out] HexStr Pointer to the string.
319 @param[in, out] HexLength The length of the string.
321 @retval EFI_SUCCESS The binary data is converted to the hexadecimal string
322 and the length of the string is updated.
323 @retval EFI_BUFFER_TOO_SMALL The string is too small.
324 @retval EFI_INVALID_PARAMETER The IP string is malformatted.
331 IN OUT CHAR8
*HexStr
,
332 IN OUT UINT32
*HexLength
337 if ((HexStr
== NULL
) || (BinBuffer
== NULL
) || (BinLength
== 0)) {
338 return EFI_INVALID_PARAMETER
;
341 if (((*HexLength
) - 3) < BinLength
* 2) {
342 *HexLength
= BinLength
* 2 + 3;
343 return EFI_BUFFER_TOO_SMALL
;
346 *HexLength
= BinLength
* 2 + 3;
348 // Prefix for Hex String.
353 for (Index
= 0; Index
< BinLength
; Index
++) {
354 HexStr
[Index
* 2 + 2] = IScsiHexString
[BinBuffer
[Index
] >> 4];
355 HexStr
[Index
* 2 + 3] = IScsiHexString
[BinBuffer
[Index
] & 0xf];
358 HexStr
[Index
* 2 + 2] = '\0';
365 Convert the hexadecimal string into a binary encoded buffer.
367 @param[in, out] BinBuffer The binary buffer.
368 @param[in, out] BinLength Length of the binary buffer.
369 @param[in] HexStr The hexadecimal string.
371 @retval EFI_SUCCESS The hexadecimal string is converted into a binary
373 @retval EFI_BUFFER_TOO_SMALL The binary buffer is too small to hold the converted data.
378 IN OUT UINT8
*BinBuffer
,
379 IN OUT UINT32
*BinLength
,
388 ZeroMem (TemStr
, sizeof (TemStr
));
391 // Find out how many hex characters the string has.
393 if ((HexStr
[0] == '0') && ((HexStr
[1] == 'x') || (HexStr
[1] == 'X'))) {
397 Length
= AsciiStrLen (HexStr
);
399 for (Index
= 0; Index
< Length
; Index
++) {
400 TemStr
[0] = HexStr
[Index
];
401 Digit
= (UINT8
) AsciiStrHexToUint64 (TemStr
);
402 if (Digit
== 0 && TemStr
[0] != '0') {
408 if ((Index
& 1) == 0) {
409 BinBuffer
[Index
/2] = Digit
;
411 BinBuffer
[Index
/2] = (UINT8
) ((BinBuffer
[Index
/2] << 4) + Digit
);
415 *BinLength
= (UINT32
) ((Index
+ 1)/2);
422 Convert the decimal-constant string or hex-constant string into a numerical value.
424 @param[in] Str String in decimal or hex.
426 @return The numerical value.
434 if ((Str
[0] == '0') && ((Str
[1] == 'x') || (Str
[1] == 'X'))) {
437 return AsciiStrHexToUintn (Str
);
440 return AsciiStrDecimalToUintn (Str
);
445 Generate random numbers.
447 @param[in, out] Rand The buffer to contain random numbers.
448 @param[in] RandLength The length of the Rand buffer.
459 while (RandLength
> 0) {
460 Random
= NET_RANDOM (NetRandomInitSeed ());
461 *Rand
++ = (UINT8
) (Random
);
468 Record the NIC info in global structure.
470 @param[in] Controller The handle of the controller.
472 @retval EFI_SUCCESS The operation is completed.
473 @retval EFI_OUT_OF_RESOURCES Do not have sufficient resources to finish this
479 IN EFI_HANDLE Controller
483 ISCSI_NIC_INFO
*NicInfo
;
485 EFI_MAC_ADDRESS MacAddr
;
490 // Get MAC address of this network device.
492 Status
= NetLibGetMacAddress (Controller
, &MacAddr
, &HwAddressSize
);
493 if (EFI_ERROR (Status
)) {
498 // Get VLAN ID of this network device.
500 VlanId
= NetLibGetVlanId (Controller
);
503 // Check whether the NIC info already exists. Return directly if so.
505 NET_LIST_FOR_EACH (Entry
, &mPrivate
->NicInfoList
) {
506 NicInfo
= NET_LIST_USER_STRUCT (Entry
, ISCSI_NIC_INFO
, Link
);
507 if (NicInfo
->HwAddressSize
== HwAddressSize
&&
508 CompareMem (&NicInfo
->PermanentAddress
, MacAddr
.Addr
, HwAddressSize
) == 0 &&
509 NicInfo
->VlanId
== VlanId
) {
510 mPrivate
->CurrentNic
= NicInfo
->NicIndex
;
514 if (mPrivate
->MaxNic
< NicInfo
->NicIndex
) {
515 mPrivate
->MaxNic
= NicInfo
->NicIndex
;
520 // Record the NIC info in private structure.
522 NicInfo
= AllocateZeroPool (sizeof (ISCSI_NIC_INFO
));
523 if (NicInfo
== NULL
) {
524 return EFI_OUT_OF_RESOURCES
;
527 CopyMem (&NicInfo
->PermanentAddress
, MacAddr
.Addr
, HwAddressSize
);
528 NicInfo
->HwAddressSize
= (UINT32
) HwAddressSize
;
529 NicInfo
->VlanId
= VlanId
;
530 NicInfo
->NicIndex
= (UINT8
) (mPrivate
->MaxNic
+ 1);
531 mPrivate
->MaxNic
= NicInfo
->NicIndex
;
534 // Get the PCI location.
536 IScsiGetNICPciLocation (
539 &NicInfo
->DeviceNumber
,
540 &NicInfo
->FunctionNumber
543 InsertTailList (&mPrivate
->NicInfoList
, &NicInfo
->Link
);
544 mPrivate
->NicCount
++;
546 mPrivate
->CurrentNic
= NicInfo
->NicIndex
;
552 Delete the recorded NIC info from global structure. Also delete corresponding
555 @param[in] Controller The handle of the controller.
557 @retval EFI_SUCCESS The operation is completed.
558 @retval EFI_NOT_FOUND The NIC info to be deleted is not recorded.
563 IN EFI_HANDLE Controller
567 ISCSI_NIC_INFO
*NicInfo
;
569 LIST_ENTRY
*NextEntry
;
570 ISCSI_ATTEMPT_CONFIG_NVDATA
*AttemptConfigData
;
571 ISCSI_NIC_INFO
*ThisNic
;
572 EFI_MAC_ADDRESS MacAddr
;
577 // Get MAC address of this network device.
579 Status
= NetLibGetMacAddress (Controller
, &MacAddr
, &HwAddressSize
);
580 if (EFI_ERROR (Status
)) {
585 // Get VLAN ID of this network device.
587 VlanId
= NetLibGetVlanId (Controller
);
590 // Check whether the NIC information exists.
594 NET_LIST_FOR_EACH (Entry
, &mPrivate
->NicInfoList
) {
595 NicInfo
= NET_LIST_USER_STRUCT (Entry
, ISCSI_NIC_INFO
, Link
);
596 if (NicInfo
->HwAddressSize
== HwAddressSize
&&
597 CompareMem (&NicInfo
->PermanentAddress
, MacAddr
.Addr
, HwAddressSize
) == 0 &&
598 NicInfo
->VlanId
== VlanId
) {
605 if (ThisNic
== NULL
) {
606 return EFI_NOT_FOUND
;
609 mPrivate
->CurrentNic
= ThisNic
->NicIndex
;
611 RemoveEntryList (&ThisNic
->Link
);
613 mPrivate
->NicCount
--;
616 // Remove all attempts related to this NIC.
618 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &mPrivate
->AttemptConfigs
) {
619 AttemptConfigData
= NET_LIST_USER_STRUCT (Entry
, ISCSI_ATTEMPT_CONFIG_NVDATA
, Link
);
620 if (AttemptConfigData
->NicIndex
== mPrivate
->CurrentNic
) {
621 RemoveEntryList (&AttemptConfigData
->Link
);
622 mPrivate
->AttemptCount
--;
624 if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED_FOR_MPIO
&& mPrivate
->MpioCount
> 0) {
625 if (--mPrivate
->MpioCount
== 0) {
626 mPrivate
->EnableMpio
= FALSE
;
629 if (AttemptConfigData
->AuthenticationType
== ISCSI_AUTH_TYPE_KRB
&& mPrivate
->Krb5MpioCount
> 0) {
630 mPrivate
->Krb5MpioCount
--;
633 } else if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED
&& mPrivate
->SinglePathCount
> 0) {
634 mPrivate
->SinglePathCount
--;
636 if (mPrivate
->ValidSinglePathCount
> 0) {
637 mPrivate
->ValidSinglePathCount
--;
641 FreePool (AttemptConfigData
);
646 // Free attempt is created but not saved to system.
648 if (mPrivate
->NewAttempt
!= NULL
) {
649 FreePool (mPrivate
->NewAttempt
);
650 mPrivate
->NewAttempt
= NULL
;
658 Get the recorded NIC info from global structure by the Index.
660 @param[in] NicIndex The index indicates the position of NIC info.
662 @return Pointer to the NIC info, or NULL if not found.
666 IScsiGetNicInfoByIndex (
671 ISCSI_NIC_INFO
*NicInfo
;
673 NET_LIST_FOR_EACH (Entry
, &mPrivate
->NicInfoList
) {
674 NicInfo
= NET_LIST_USER_STRUCT (Entry
, ISCSI_NIC_INFO
, Link
);
675 if (NicInfo
->NicIndex
== NicIndex
) {
685 Get the NIC's PCI location and return it accroding to the composited
686 format defined in iSCSI Boot Firmware Table.
688 @param[in] Controller The handle of the controller.
689 @param[out] Bus The bus number.
690 @param[out] Device The device number.
691 @param[out] Function The function number.
693 @return The composited representation of the NIC PCI location.
697 IScsiGetNICPciLocation (
698 IN EFI_HANDLE Controller
,
705 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
706 EFI_HANDLE PciIoHandle
;
707 EFI_PCI_IO_PROTOCOL
*PciIo
;
710 Status
= gBS
->HandleProtocol (
712 &gEfiDevicePathProtocolGuid
,
713 (VOID
**) &DevicePath
715 if (EFI_ERROR (Status
)) {
719 Status
= gBS
->LocateDevicePath (
720 &gEfiPciIoProtocolGuid
,
724 if (EFI_ERROR (Status
)) {
728 Status
= gBS
->HandleProtocol (PciIoHandle
, &gEfiPciIoProtocolGuid
, (VOID
**) &PciIo
);
729 if (EFI_ERROR (Status
)) {
733 Status
= PciIo
->GetLocation (PciIo
, &Segment
, Bus
, Device
, Function
);
734 if (EFI_ERROR (Status
)) {
738 return (UINT16
) ((*Bus
<< 8) | (*Device
<< 3) | *Function
);
743 Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
744 buffer, and the size of the buffer. If failure, return NULL.
746 @param[in] Name String part of EFI variable name.
747 @param[in] VendorGuid GUID part of EFI variable name.
748 @param[out] VariableSize Returns the size of the EFI variable that was read.
750 @return Dynamically allocated memory that contains a copy of the EFI variable.
751 @return Caller is responsible freeing the buffer.
752 @retval NULL Variable was not read.
756 IScsiGetVariableAndSize (
758 IN EFI_GUID
*VendorGuid
,
759 OUT UINTN
*VariableSize
769 // Pass in a zero size buffer to find the required buffer size.
772 Status
= gRT
->GetVariable (Name
, VendorGuid
, NULL
, &BufferSize
, Buffer
);
773 if (Status
== EFI_BUFFER_TOO_SMALL
) {
775 // Allocate the buffer to return
777 Buffer
= AllocateZeroPool (BufferSize
);
778 if (Buffer
== NULL
) {
782 // Read variable into the allocated buffer.
784 Status
= gRT
->GetVariable (Name
, VendorGuid
, NULL
, &BufferSize
, Buffer
);
785 if (EFI_ERROR (Status
)) {
790 *VariableSize
= BufferSize
;
796 Create the iSCSI driver data.
798 @param[in] Image The handle of the driver image.
799 @param[in] Controller The handle of the controller.
801 @return The iSCSI driver data created.
802 @retval NULL Other errors as indicated.
806 IScsiCreateDriverData (
808 IN EFI_HANDLE Controller
811 ISCSI_DRIVER_DATA
*Private
;
814 Private
= AllocateZeroPool (sizeof (ISCSI_DRIVER_DATA
));
815 if (Private
== NULL
) {
819 Private
->Signature
= ISCSI_DRIVER_DATA_SIGNATURE
;
820 Private
->Image
= Image
;
821 Private
->Controller
= Controller
;
822 Private
->Session
= NULL
;
825 // Create an event to be signaled when the BS to RT transition is triggerd so
826 // as to abort the iSCSI session.
828 Status
= gBS
->CreateEventEx (
831 IScsiOnExitBootService
,
833 &gEfiEventExitBootServicesGuid
,
834 &Private
->ExitBootServiceEvent
836 if (EFI_ERROR (Status
)) {
841 Private
->ExtScsiPassThruHandle
= NULL
;
842 CopyMem(&Private
->IScsiExtScsiPassThru
, &gIScsiExtScsiPassThruProtocolTemplate
, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL
));
845 // 0 is designated to the TargetId, so use another value for the AdapterId.
847 Private
->ExtScsiPassThruMode
.AdapterId
= 2;
848 Private
->ExtScsiPassThruMode
.Attributes
= EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
| EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
849 Private
->ExtScsiPassThruMode
.IoAlign
= 4;
850 Private
->IScsiExtScsiPassThru
.Mode
= &Private
->ExtScsiPassThruMode
;
857 Clean the iSCSI driver data.
859 @param[in] Private The iSCSI driver data.
863 IScsiCleanDriverData (
864 IN ISCSI_DRIVER_DATA
*Private
869 if (Private
->DevicePath
!= NULL
) {
870 gBS
->UninstallProtocolInterface (
871 Private
->ExtScsiPassThruHandle
,
872 &gEfiDevicePathProtocolGuid
,
876 FreePool (Private
->DevicePath
);
879 if (Private
->ExtScsiPassThruHandle
!= NULL
) {
880 Status
= gBS
->UninstallProtocolInterface (
881 Private
->ExtScsiPassThruHandle
,
882 &gEfiExtScsiPassThruProtocolGuid
,
883 &Private
->IScsiExtScsiPassThru
885 if (!EFI_ERROR (Status
)) {
886 mPrivate
->OneSessionEstablished
= FALSE
;
890 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
896 Check wheather the Controller handle is configured to use DHCP protocol.
898 @param[in] Controller The handle of the controller.
899 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
901 @retval TRUE The handle of the controller need the Dhcp protocol.
902 @retval FALSE The handle of the controller does not need the Dhcp protocol.
906 IScsiDhcpIsConfigured (
907 IN EFI_HANDLE Controller
,
911 ISCSI_ATTEMPT_CONFIG_NVDATA
*AttemptTmp
;
912 UINT8
*AttemptConfigOrder
;
913 UINTN AttemptConfigOrderSize
;
916 EFI_MAC_ADDRESS MacAddr
;
919 CHAR16 MacString
[ISCSI_MAX_MAC_STRING_LEN
];
920 CHAR16 AttemptName
[ISCSI_NAME_IFR_MAX_SIZE
];
922 AttemptConfigOrder
= IScsiGetVariableAndSize (
925 &AttemptConfigOrderSize
927 if (AttemptConfigOrder
== NULL
|| AttemptConfigOrderSize
== 0) {
932 // Get MAC address of this network device.
934 Status
= NetLibGetMacAddress (Controller
, &MacAddr
, &HwAddressSize
);
935 if(EFI_ERROR (Status
)) {
939 // Get VLAN ID of this network device.
941 VlanId
= NetLibGetVlanId (Controller
);
942 IScsiMacAddrToStr (&MacAddr
, (UINT32
) HwAddressSize
, VlanId
, MacString
);
944 for (Index
= 0; Index
< AttemptConfigOrderSize
/ sizeof (UINT8
); Index
++) {
950 (UINTN
) AttemptConfigOrder
[Index
]
952 Status
= GetVariable2 (
954 &gEfiIScsiInitiatorNameProtocolGuid
,
958 if(AttemptTmp
== NULL
|| EFI_ERROR (Status
)) {
962 ASSERT (AttemptConfigOrder
[Index
] == AttemptTmp
->AttemptConfigIndex
);
964 if (AttemptTmp
->SessionConfigData
.Enabled
== ISCSI_DISABLED
) {
965 FreePool (AttemptTmp
);
969 if (AttemptTmp
->SessionConfigData
.IpMode
!= IP_MODE_AUTOCONFIG
&&
970 AttemptTmp
->SessionConfigData
.IpMode
!= ((IpVersion
== IP_VERSION_4
) ? IP_MODE_IP4
: IP_MODE_IP6
)) {
971 FreePool (AttemptTmp
);
975 if(AttemptTmp
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
||
976 AttemptTmp
->SessionConfigData
.InitiatorInfoFromDhcp
== TRUE
||
977 AttemptTmp
->SessionConfigData
.TargetInfoFromDhcp
== TRUE
) {
978 FreePool (AttemptTmp
);
979 FreePool (AttemptConfigOrder
);
983 FreePool (AttemptTmp
);
986 FreePool (AttemptConfigOrder
);
991 Get the various configuration data.
993 @param[in] Private The iSCSI driver data.
995 @retval EFI_SUCCESS The configuration data is retrieved.
996 @retval EFI_NOT_FOUND This iSCSI driver is not configured yet.
1000 IScsiGetConfigData (
1001 IN ISCSI_DRIVER_DATA
*Private
1005 CHAR16 MacString
[ISCSI_MAX_MAC_STRING_LEN
];
1007 ISCSI_NIC_INFO
*NicInfo
;
1008 ISCSI_ATTEMPT_CONFIG_NVDATA
*AttemptConfigData
;
1009 ISCSI_ATTEMPT_CONFIG_NVDATA
*AttemptTmp
;
1010 UINT8
*AttemptConfigOrder
;
1011 UINTN AttemptConfigOrderSize
;
1012 CHAR16 IScsiMode
[64];
1016 // There should be at least one attempt configured.
1018 AttemptConfigOrder
= IScsiGetVariableAndSize (
1021 &AttemptConfigOrderSize
1023 if (AttemptConfigOrder
== NULL
|| AttemptConfigOrderSize
== 0) {
1024 return EFI_NOT_FOUND
;
1028 // Get the iSCSI Initiator Name.
1030 mPrivate
->InitiatorNameLength
= ISCSI_NAME_MAX_SIZE
;
1031 Status
= gIScsiInitiatorName
.Get (
1032 &gIScsiInitiatorName
,
1033 &mPrivate
->InitiatorNameLength
,
1034 mPrivate
->InitiatorName
1036 if (EFI_ERROR (Status
)) {
1041 // Get the normal configuration.
1043 for (Index
= 0; Index
< AttemptConfigOrderSize
/ sizeof (UINT8
); Index
++) {
1046 // Check whether the attempt exists in AttemptConfig.
1048 AttemptTmp
= IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder
[Index
]);
1049 if (AttemptTmp
!= NULL
&& AttemptTmp
->SessionConfigData
.Enabled
== ISCSI_DISABLED
) {
1051 } else if (AttemptTmp
!= NULL
&& AttemptTmp
->SessionConfigData
.Enabled
!= ISCSI_DISABLED
) {
1053 // Check the autoconfig path to see whether it should be retried.
1055 if (AttemptTmp
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
&&
1056 AttemptTmp
->AutoConfigureMode
!= IP_MODE_AUTOCONFIG_SUCCESS
) {
1057 if (mPrivate
->Ipv6Flag
&&
1058 AttemptTmp
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP6
) {
1060 // Autoconfigure for IP6 already attempted but failed. Do not try again.
1063 } else if (!mPrivate
->Ipv6Flag
&&
1064 AttemptTmp
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP4
) {
1066 // Autoconfigure for IP4 already attempted but failed. Do not try again.
1071 // Try another approach for this autoconfigure path.
1073 AttemptTmp
->AutoConfigureMode
=
1074 (UINT8
) (mPrivate
->Ipv6Flag
? IP_MODE_AUTOCONFIG_IP6
: IP_MODE_AUTOCONFIG_IP4
);
1075 AttemptTmp
->SessionConfigData
.InitiatorInfoFromDhcp
= TRUE
;
1076 AttemptTmp
->SessionConfigData
.TargetInfoFromDhcp
= TRUE
;
1077 AttemptTmp
->DhcpSuccess
= FALSE
;
1080 // Get some information from the dhcp server.
1082 if (!mPrivate
->Ipv6Flag
) {
1083 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, AttemptTmp
);
1084 if (!EFI_ERROR (Status
)) {
1085 AttemptTmp
->DhcpSuccess
= TRUE
;
1088 Status
= IScsiDoDhcp6 (Private
->Image
, Private
->Controller
, AttemptTmp
);
1089 if (!EFI_ERROR (Status
)) {
1090 AttemptTmp
->DhcpSuccess
= TRUE
;
1095 // Refresh the state of this attempt to NVR.
1097 AsciiStrToUnicodeStr (AttemptTmp
->MacString
, MacString
);
1099 mPrivate
->PortString
,
1100 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
1103 (UINTN
) AttemptTmp
->AttemptConfigIndex
1107 mPrivate
->PortString
,
1108 &gEfiIScsiInitiatorNameProtocolGuid
,
1109 ISCSI_CONFIG_VAR_ATTR
,
1110 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA
),
1116 } else if (AttemptTmp
->SessionConfigData
.InitiatorInfoFromDhcp
&& !AttemptTmp
->ValidPath
) {
1118 // Get DHCP information for already added, but failed, attempt.
1120 AttemptTmp
->DhcpSuccess
= FALSE
;
1121 if (!mPrivate
->Ipv6Flag
&& (AttemptTmp
->SessionConfigData
.IpMode
== IP_MODE_IP4
)) {
1122 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, AttemptTmp
);
1123 if (!EFI_ERROR (Status
)) {
1124 AttemptTmp
->DhcpSuccess
= TRUE
;
1126 } else if (mPrivate
->Ipv6Flag
&& (AttemptTmp
->SessionConfigData
.IpMode
== IP_MODE_IP6
)) {
1127 Status
= IScsiDoDhcp6 (Private
->Image
, Private
->Controller
, AttemptTmp
);
1128 if (!EFI_ERROR (Status
)) {
1129 AttemptTmp
->DhcpSuccess
= TRUE
;
1134 // Refresh the state of this attempt to NVR.
1136 AsciiStrToUnicodeStr (AttemptTmp
->MacString
, MacString
);
1138 mPrivate
->PortString
,
1139 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
1142 (UINTN
) AttemptTmp
->AttemptConfigIndex
1146 mPrivate
->PortString
,
1147 &gEfiIScsiInitiatorNameProtocolGuid
,
1148 ISCSI_CONFIG_VAR_ATTR
,
1149 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA
),
1161 // This attempt does not exist in AttemptConfig. Try to add a new one.
1164 NicInfo
= IScsiGetNicInfoByIndex (mPrivate
->CurrentNic
);
1165 ASSERT (NicInfo
!= NULL
);
1166 IScsiMacAddrToStr (&NicInfo
->PermanentAddress
, NicInfo
->HwAddressSize
, NicInfo
->VlanId
, MacString
);
1168 mPrivate
->PortString
,
1172 (UINTN
) AttemptConfigOrder
[Index
]
1176 mPrivate
->PortString
,
1177 &gEfiIScsiInitiatorNameProtocolGuid
,
1178 (VOID
**)&AttemptConfigData
,
1182 if (AttemptConfigData
== NULL
) {
1186 ASSERT (AttemptConfigOrder
[Index
] == AttemptConfigData
->AttemptConfigIndex
);
1188 AttemptConfigData
->NicIndex
= NicInfo
->NicIndex
;
1189 AttemptConfigData
->DhcpSuccess
= FALSE
;
1190 AttemptConfigData
->ValidiBFTPath
= (BOOLEAN
) (mPrivate
->EnableMpio
? TRUE
: FALSE
);
1191 AttemptConfigData
->ValidPath
= FALSE
;
1193 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
) {
1194 AttemptConfigData
->SessionConfigData
.InitiatorInfoFromDhcp
= TRUE
;
1195 AttemptConfigData
->SessionConfigData
.TargetInfoFromDhcp
= TRUE
;
1197 AttemptConfigData
->AutoConfigureMode
=
1198 (UINT8
) (mPrivate
->Ipv6Flag
? IP_MODE_AUTOCONFIG_IP6
: IP_MODE_AUTOCONFIG_IP4
);
1202 // Get some information from dhcp server.
1204 if (AttemptConfigData
->SessionConfigData
.Enabled
!= ISCSI_DISABLED
&&
1205 AttemptConfigData
->SessionConfigData
.InitiatorInfoFromDhcp
) {
1207 if (!mPrivate
->Ipv6Flag
&&
1208 (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP4
||
1209 AttemptConfigData
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP4
)) {
1210 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, AttemptConfigData
);
1211 if (!EFI_ERROR (Status
)) {
1212 AttemptConfigData
->DhcpSuccess
= TRUE
;
1214 } else if (mPrivate
->Ipv6Flag
&&
1215 (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP6
||
1216 AttemptConfigData
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP6
)) {
1217 Status
= IScsiDoDhcp6 (Private
->Image
, Private
->Controller
, AttemptConfigData
);
1218 if (!EFI_ERROR (Status
)) {
1219 AttemptConfigData
->DhcpSuccess
= TRUE
;
1224 // Refresh the state of this attempt to NVR.
1226 AsciiStrToUnicodeStr (AttemptConfigData
->MacString
, MacString
);
1228 mPrivate
->PortString
,
1229 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
1232 (UINTN
) AttemptConfigData
->AttemptConfigIndex
1236 mPrivate
->PortString
,
1237 &gEfiIScsiInitiatorNameProtocolGuid
,
1238 ISCSI_CONFIG_VAR_ATTR
,
1239 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA
),
1245 // Update Attempt Help Info.
1248 if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_DISABLED
) {
1249 UnicodeSPrint (IScsiMode
, 64, L
"Disabled");
1250 } else if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED
) {
1251 UnicodeSPrint (IScsiMode
, 64, L
"Enabled");
1252 } else if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED_FOR_MPIO
) {
1253 UnicodeSPrint (IScsiMode
, 64, L
"Enabled for MPIO");
1256 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP4
) {
1257 UnicodeSPrint (IpMode
, 64, L
"IP4");
1258 } else if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP6
) {
1259 UnicodeSPrint (IpMode
, 64, L
"IP6");
1260 } else if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
) {
1261 UnicodeSPrint (IpMode
, 64, L
"Autoconfigure");
1265 mPrivate
->PortString
,
1266 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
1267 L
"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s",
1270 NicInfo
->DeviceNumber
,
1271 NicInfo
->FunctionNumber
,
1276 AttemptConfigData
->AttemptTitleHelpToken
= HiiSetString (
1277 mCallbackInfo
->RegisteredHandle
,
1279 mPrivate
->PortString
,
1282 ASSERT (AttemptConfigData
->AttemptTitleHelpToken
!= 0);
1285 // Record the attempt in global link list.
1287 InsertTailList (&mPrivate
->AttemptConfigs
, &AttemptConfigData
->Link
);
1288 mPrivate
->AttemptCount
++;
1290 if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED_FOR_MPIO
) {
1291 mPrivate
->MpioCount
++;
1292 mPrivate
->EnableMpio
= TRUE
;
1294 if (AttemptConfigData
->AuthenticationType
== ISCSI_AUTH_TYPE_KRB
) {
1295 mPrivate
->Krb5MpioCount
++;
1297 } else if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED
) {
1298 mPrivate
->SinglePathCount
++;
1303 // Reorder the AttemptConfig by the configured order.
1305 for (Index
= 0; Index
< AttemptConfigOrderSize
/ sizeof (UINT8
); Index
++) {
1306 AttemptConfigData
= IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder
[Index
]);
1307 if (AttemptConfigData
== NULL
) {
1311 RemoveEntryList (&AttemptConfigData
->Link
);
1312 InsertTailList (&mPrivate
->AttemptConfigs
, &AttemptConfigData
->Link
);
1316 // Update the Main Form.
1318 IScsiConfigUpdateAttempt ();
1320 FreePool (AttemptConfigOrder
);
1323 // There should be at least one attempt configuration.
1325 if (!mPrivate
->EnableMpio
) {
1326 if (mPrivate
->SinglePathCount
== 0) {
1327 return EFI_NOT_FOUND
;
1329 mPrivate
->ValidSinglePathCount
= mPrivate
->SinglePathCount
;
1337 Get the device path of the iSCSI tcp connection and update it.
1339 @param Session The iSCSI session.
1341 @return The updated device path.
1342 @retval NULL Other errors as indicated.
1345 EFI_DEVICE_PATH_PROTOCOL
*
1346 IScsiGetTcpConnDevicePath (
1347 IN ISCSI_SESSION
*Session
1350 ISCSI_CONNECTION
*Conn
;
1351 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1353 EFI_DEV_PATH
*DPathNode
;
1355 if (Session
->State
!= SESSION_STATE_LOGGED_IN
) {
1359 Conn
= NET_LIST_USER_STRUCT_S (
1360 Session
->Conns
.ForwardLink
,
1363 ISCSI_CONNECTION_SIGNATURE
1366 Status
= gBS
->HandleProtocol (
1368 &gEfiDevicePathProtocolGuid
,
1369 (VOID
**) &DevicePath
1371 if (EFI_ERROR (Status
)) {
1377 DevicePath
= DuplicateDevicePath (DevicePath
);
1378 if (DevicePath
== NULL
) {
1382 DPathNode
= (EFI_DEV_PATH
*) DevicePath
;
1384 while (!IsDevicePathEnd (&DPathNode
->DevPath
)) {
1385 if (DevicePathType (&DPathNode
->DevPath
) == MESSAGING_DEVICE_PATH
) {
1386 if (!Conn
->Ipv6Flag
&& DevicePathSubType (&DPathNode
->DevPath
) == MSG_IPv4_DP
) {
1387 DPathNode
->Ipv4
.LocalPort
= 0;
1389 DPathNode
->Ipv4
.StaticIpAddress
=
1390 (BOOLEAN
) (!Session
->ConfigData
->SessionConfigData
.InitiatorInfoFromDhcp
);
1393 &DPathNode
->Ipv4
.GatewayIpAddress
,
1394 &Session
->ConfigData
->SessionConfigData
.Gateway
1398 &DPathNode
->Ipv4
.SubnetMask
,
1399 &Session
->ConfigData
->SessionConfigData
.SubnetMask
1402 } else if (Conn
->Ipv6Flag
&& DevicePathSubType (&DPathNode
->DevPath
) == MSG_IPv6_DP
) {
1403 DPathNode
->Ipv6
.LocalPort
= 0;
1404 DPathNode
->Ipv6
.IpAddressOrigin
= 0;
1405 DPathNode
->Ipv6
.PrefixLength
= IP6_PREFIX_LENGTH
;
1406 ZeroMem (&DPathNode
->Ipv6
.GatewayIpAddress
, sizeof (EFI_IPv6_ADDRESS
));
1411 DPathNode
= (EFI_DEV_PATH
*) NextDevicePathNode (&DPathNode
->DevPath
);
1419 Abort the session when the transition from BS to RT is initiated.
1421 @param[in] Event The event signaled.
1422 @param[in] Context The iSCSI driver data.
1427 IScsiOnExitBootService (
1432 ISCSI_DRIVER_DATA
*Private
;
1434 Private
= (ISCSI_DRIVER_DATA
*) Context
;
1435 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
1437 if (Private
->Session
!= NULL
) {
1438 IScsiSessionAbort (Private
->Session
);
1443 Tests whether a controller handle is being managed by IScsi driver.
1445 This function tests whether the driver specified by DriverBindingHandle is
1446 currently managing the controller specified by ControllerHandle. This test
1447 is performed by evaluating if the the protocol specified by ProtocolGuid is
1448 present on ControllerHandle and is was opened by DriverBindingHandle and Nic
1449 Device handle with an attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
1450 If ProtocolGuid is NULL, then ASSERT().
1452 @param ControllerHandle A handle for a controller to test.
1453 @param DriverBindingHandle Specifies the driver binding handle for the
1455 @param ProtocolGuid Specifies the protocol that the driver specified
1456 by DriverBindingHandle opens in its Start()
1459 @retval EFI_SUCCESS ControllerHandle is managed by the driver
1460 specified by DriverBindingHandle.
1461 @retval EFI_UNSUPPORTED ControllerHandle is not managed by the driver
1462 specified by DriverBindingHandle.
1467 IScsiTestManagedDevice (
1468 IN EFI_HANDLE ControllerHandle
,
1469 IN EFI_HANDLE DriverBindingHandle
,
1470 IN EFI_GUID
*ProtocolGuid
1474 VOID
*ManagedInterface
;
1475 EFI_HANDLE NicControllerHandle
;
1477 ASSERT (ProtocolGuid
!= NULL
);
1479 NicControllerHandle
= NetLibGetNicHandle (ControllerHandle
, ProtocolGuid
);
1480 if (NicControllerHandle
== NULL
) {
1481 return EFI_UNSUPPORTED
;
1484 Status
= gBS
->OpenProtocol (
1486 (EFI_GUID
*) ProtocolGuid
,
1488 DriverBindingHandle
,
1489 NicControllerHandle
,
1490 EFI_OPEN_PROTOCOL_BY_DRIVER
1492 if (!EFI_ERROR (Status
)) {
1493 gBS
->CloseProtocol (
1495 (EFI_GUID
*) ProtocolGuid
,
1496 DriverBindingHandle
,
1499 return EFI_UNSUPPORTED
;
1502 if (Status
!= EFI_ALREADY_STARTED
) {
1503 return EFI_UNSUPPORTED
;