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 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
);
894 Check wheather the Controller handle is configured to use DHCP protocol.
896 @param[in] Controller The handle of the controller.
897 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
899 @retval TRUE The handle of the controller need the Dhcp protocol.
900 @retval FALSE The handle of the controller does not need the Dhcp protocol.
904 IScsiDhcpIsConfigured (
905 IN EFI_HANDLE Controller
,
909 ISCSI_ATTEMPT_CONFIG_NVDATA
*AttemptTmp
;
910 UINT8
*AttemptConfigOrder
;
911 UINTN AttemptConfigOrderSize
;
914 EFI_MAC_ADDRESS MacAddr
;
917 CHAR16 MacString
[ISCSI_MAX_MAC_STRING_LEN
];
918 CHAR16 AttemptName
[ISCSI_NAME_IFR_MAX_SIZE
];
920 AttemptConfigOrder
= IScsiGetVariableAndSize (
923 &AttemptConfigOrderSize
925 if (AttemptConfigOrder
== NULL
|| AttemptConfigOrderSize
== 0) {
930 // Get MAC address of this network device.
932 Status
= NetLibGetMacAddress (Controller
, &MacAddr
, &HwAddressSize
);
933 if(EFI_ERROR (Status
)) {
937 // Get VLAN ID of this network device.
939 VlanId
= NetLibGetVlanId (Controller
);
940 IScsiMacAddrToStr (&MacAddr
, (UINT32
) HwAddressSize
, VlanId
, MacString
);
942 for (Index
= 0; Index
< AttemptConfigOrderSize
/ sizeof (UINT8
); Index
++) {
948 (UINTN
) AttemptConfigOrder
[Index
]
950 Status
= GetVariable2 (
952 &gEfiIScsiInitiatorNameProtocolGuid
,
956 if(AttemptTmp
== NULL
|| EFI_ERROR (Status
)) {
960 ASSERT (AttemptConfigOrder
[Index
] == AttemptTmp
->AttemptConfigIndex
);
962 if (AttemptTmp
->SessionConfigData
.Enabled
== ISCSI_DISABLED
) {
963 FreePool (AttemptTmp
);
967 if (AttemptTmp
->SessionConfigData
.IpMode
!= IP_MODE_AUTOCONFIG
&&
968 AttemptTmp
->SessionConfigData
.IpMode
!= ((IpVersion
== IP_VERSION_4
) ? IP_MODE_IP4
: IP_MODE_IP6
)) {
969 FreePool (AttemptTmp
);
973 if(AttemptTmp
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
||
974 AttemptTmp
->SessionConfigData
.InitiatorInfoFromDhcp
== TRUE
||
975 AttemptTmp
->SessionConfigData
.TargetInfoFromDhcp
== TRUE
) {
976 FreePool (AttemptTmp
);
977 FreePool (AttemptConfigOrder
);
981 FreePool (AttemptTmp
);
984 FreePool (AttemptConfigOrder
);
989 Get the various configuration data.
991 @param[in] Private The iSCSI driver data.
993 @retval EFI_SUCCESS The configuration data is retrieved.
994 @retval EFI_NOT_FOUND This iSCSI driver is not configured yet.
999 IN ISCSI_DRIVER_DATA
*Private
1003 CHAR16 MacString
[ISCSI_MAX_MAC_STRING_LEN
];
1005 ISCSI_NIC_INFO
*NicInfo
;
1006 ISCSI_ATTEMPT_CONFIG_NVDATA
*AttemptConfigData
;
1007 ISCSI_ATTEMPT_CONFIG_NVDATA
*AttemptTmp
;
1008 UINT8
*AttemptConfigOrder
;
1009 UINTN AttemptConfigOrderSize
;
1010 CHAR16 IScsiMode
[64];
1014 // There should be at least one attempt configured.
1016 AttemptConfigOrder
= IScsiGetVariableAndSize (
1019 &AttemptConfigOrderSize
1021 if (AttemptConfigOrder
== NULL
|| AttemptConfigOrderSize
== 0) {
1022 return EFI_NOT_FOUND
;
1026 // Get the iSCSI Initiator Name.
1028 mPrivate
->InitiatorNameLength
= ISCSI_NAME_MAX_SIZE
;
1029 Status
= gIScsiInitiatorName
.Get (
1030 &gIScsiInitiatorName
,
1031 &mPrivate
->InitiatorNameLength
,
1032 mPrivate
->InitiatorName
1034 if (EFI_ERROR (Status
)) {
1039 // Get the normal configuration.
1041 for (Index
= 0; Index
< AttemptConfigOrderSize
/ sizeof (UINT8
); Index
++) {
1044 // Check whether the attempt exists in AttemptConfig.
1046 AttemptTmp
= IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder
[Index
]);
1047 if (AttemptTmp
!= NULL
&& AttemptTmp
->SessionConfigData
.Enabled
== ISCSI_DISABLED
) {
1049 } else if (AttemptTmp
!= NULL
&& AttemptTmp
->SessionConfigData
.Enabled
!= ISCSI_DISABLED
) {
1051 // Check the autoconfig path to see whether it should be retried.
1053 if (AttemptTmp
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
&&
1054 AttemptTmp
->AutoConfigureMode
!= IP_MODE_AUTOCONFIG_SUCCESS
) {
1055 if (mPrivate
->Ipv6Flag
&&
1056 AttemptTmp
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP6
) {
1058 // Autoconfigure for IP6 already attempted but failed. Do not try again.
1061 } else if (!mPrivate
->Ipv6Flag
&&
1062 AttemptTmp
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP4
) {
1064 // Autoconfigure for IP4 already attempted but failed. Do not try again.
1069 // Try another approach for this autoconfigure path.
1071 AttemptTmp
->AutoConfigureMode
=
1072 (UINT8
) (mPrivate
->Ipv6Flag
? IP_MODE_AUTOCONFIG_IP6
: IP_MODE_AUTOCONFIG_IP4
);
1073 AttemptTmp
->SessionConfigData
.InitiatorInfoFromDhcp
= TRUE
;
1074 AttemptTmp
->SessionConfigData
.TargetInfoFromDhcp
= TRUE
;
1075 AttemptTmp
->DhcpSuccess
= FALSE
;
1078 // Get some information from the dhcp server.
1080 if (!mPrivate
->Ipv6Flag
) {
1081 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, AttemptTmp
);
1082 if (!EFI_ERROR (Status
)) {
1083 AttemptTmp
->DhcpSuccess
= TRUE
;
1086 Status
= IScsiDoDhcp6 (Private
->Image
, Private
->Controller
, AttemptTmp
);
1087 if (!EFI_ERROR (Status
)) {
1088 AttemptTmp
->DhcpSuccess
= TRUE
;
1093 // Refresh the state of this attempt to NVR.
1095 AsciiStrToUnicodeStr (AttemptTmp
->MacString
, MacString
);
1097 mPrivate
->PortString
,
1098 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
1101 (UINTN
) AttemptTmp
->AttemptConfigIndex
1105 mPrivate
->PortString
,
1106 &gEfiIScsiInitiatorNameProtocolGuid
,
1107 ISCSI_CONFIG_VAR_ATTR
,
1108 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA
),
1114 } else if (AttemptTmp
->SessionConfigData
.InitiatorInfoFromDhcp
&& !AttemptTmp
->ValidPath
) {
1116 // Get DHCP information for already added, but failed, attempt.
1118 AttemptTmp
->DhcpSuccess
= FALSE
;
1119 if (!mPrivate
->Ipv6Flag
&& (AttemptTmp
->SessionConfigData
.IpMode
== IP_MODE_IP4
)) {
1120 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, AttemptTmp
);
1121 if (!EFI_ERROR (Status
)) {
1122 AttemptTmp
->DhcpSuccess
= TRUE
;
1124 } else if (mPrivate
->Ipv6Flag
&& (AttemptTmp
->SessionConfigData
.IpMode
== IP_MODE_IP6
)) {
1125 Status
= IScsiDoDhcp6 (Private
->Image
, Private
->Controller
, AttemptTmp
);
1126 if (!EFI_ERROR (Status
)) {
1127 AttemptTmp
->DhcpSuccess
= TRUE
;
1132 // Refresh the state of this attempt to NVR.
1134 AsciiStrToUnicodeStr (AttemptTmp
->MacString
, MacString
);
1136 mPrivate
->PortString
,
1137 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
1140 (UINTN
) AttemptTmp
->AttemptConfigIndex
1144 mPrivate
->PortString
,
1145 &gEfiIScsiInitiatorNameProtocolGuid
,
1146 ISCSI_CONFIG_VAR_ATTR
,
1147 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA
),
1159 // This attempt does not exist in AttemptConfig. Try to add a new one.
1162 NicInfo
= IScsiGetNicInfoByIndex (mPrivate
->CurrentNic
);
1163 ASSERT (NicInfo
!= NULL
);
1164 IScsiMacAddrToStr (&NicInfo
->PermanentAddress
, NicInfo
->HwAddressSize
, NicInfo
->VlanId
, MacString
);
1166 mPrivate
->PortString
,
1170 (UINTN
) AttemptConfigOrder
[Index
]
1174 mPrivate
->PortString
,
1175 &gEfiIScsiInitiatorNameProtocolGuid
,
1176 (VOID
**)&AttemptConfigData
,
1180 if (AttemptConfigData
== NULL
) {
1184 ASSERT (AttemptConfigOrder
[Index
] == AttemptConfigData
->AttemptConfigIndex
);
1186 AttemptConfigData
->NicIndex
= NicInfo
->NicIndex
;
1187 AttemptConfigData
->DhcpSuccess
= FALSE
;
1188 AttemptConfigData
->ValidiBFTPath
= (BOOLEAN
) (mPrivate
->EnableMpio
? TRUE
: FALSE
);
1189 AttemptConfigData
->ValidPath
= FALSE
;
1191 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
) {
1192 AttemptConfigData
->SessionConfigData
.InitiatorInfoFromDhcp
= TRUE
;
1193 AttemptConfigData
->SessionConfigData
.TargetInfoFromDhcp
= TRUE
;
1195 AttemptConfigData
->AutoConfigureMode
=
1196 (UINT8
) (mPrivate
->Ipv6Flag
? IP_MODE_AUTOCONFIG_IP6
: IP_MODE_AUTOCONFIG_IP4
);
1200 // Get some information from dhcp server.
1202 if (AttemptConfigData
->SessionConfigData
.Enabled
!= ISCSI_DISABLED
&&
1203 AttemptConfigData
->SessionConfigData
.InitiatorInfoFromDhcp
) {
1205 if (!mPrivate
->Ipv6Flag
&&
1206 (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP4
||
1207 AttemptConfigData
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP4
)) {
1208 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, AttemptConfigData
);
1209 if (!EFI_ERROR (Status
)) {
1210 AttemptConfigData
->DhcpSuccess
= TRUE
;
1212 } else if (mPrivate
->Ipv6Flag
&&
1213 (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP6
||
1214 AttemptConfigData
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP6
)) {
1215 Status
= IScsiDoDhcp6 (Private
->Image
, Private
->Controller
, AttemptConfigData
);
1216 if (!EFI_ERROR (Status
)) {
1217 AttemptConfigData
->DhcpSuccess
= TRUE
;
1222 // Refresh the state of this attempt to NVR.
1224 AsciiStrToUnicodeStr (AttemptConfigData
->MacString
, MacString
);
1226 mPrivate
->PortString
,
1227 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
1230 (UINTN
) AttemptConfigData
->AttemptConfigIndex
1234 mPrivate
->PortString
,
1235 &gEfiIScsiInitiatorNameProtocolGuid
,
1236 ISCSI_CONFIG_VAR_ATTR
,
1237 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA
),
1243 // Update Attempt Help Info.
1246 if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_DISABLED
) {
1247 UnicodeSPrint (IScsiMode
, 64, L
"Disabled");
1248 } else if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED
) {
1249 UnicodeSPrint (IScsiMode
, 64, L
"Enabled");
1250 } else if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED_FOR_MPIO
) {
1251 UnicodeSPrint (IScsiMode
, 64, L
"Enabled for MPIO");
1254 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP4
) {
1255 UnicodeSPrint (IpMode
, 64, L
"IP4");
1256 } else if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP6
) {
1257 UnicodeSPrint (IpMode
, 64, L
"IP6");
1258 } else if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
) {
1259 UnicodeSPrint (IpMode
, 64, L
"Autoconfigure");
1263 mPrivate
->PortString
,
1264 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
1265 L
"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s",
1268 NicInfo
->DeviceNumber
,
1269 NicInfo
->FunctionNumber
,
1274 AttemptConfigData
->AttemptTitleHelpToken
= HiiSetString (
1275 mCallbackInfo
->RegisteredHandle
,
1277 mPrivate
->PortString
,
1280 ASSERT (AttemptConfigData
->AttemptTitleHelpToken
!= 0);
1283 // Record the attempt in global link list.
1285 InsertTailList (&mPrivate
->AttemptConfigs
, &AttemptConfigData
->Link
);
1286 mPrivate
->AttemptCount
++;
1288 if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED_FOR_MPIO
) {
1289 mPrivate
->MpioCount
++;
1290 mPrivate
->EnableMpio
= TRUE
;
1292 if (AttemptConfigData
->AuthenticationType
== ISCSI_AUTH_TYPE_KRB
) {
1293 mPrivate
->Krb5MpioCount
++;
1295 } else if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED
) {
1296 mPrivate
->SinglePathCount
++;
1301 // Reorder the AttemptConfig by the configured order.
1303 for (Index
= 0; Index
< AttemptConfigOrderSize
/ sizeof (UINT8
); Index
++) {
1304 AttemptConfigData
= IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder
[Index
]);
1305 if (AttemptConfigData
== NULL
) {
1309 RemoveEntryList (&AttemptConfigData
->Link
);
1310 InsertTailList (&mPrivate
->AttemptConfigs
, &AttemptConfigData
->Link
);
1314 // Update the Main Form.
1316 IScsiConfigUpdateAttempt ();
1318 FreePool (AttemptConfigOrder
);
1321 // There should be at least one attempt configuration.
1323 if (!mPrivate
->EnableMpio
) {
1324 if (mPrivate
->SinglePathCount
== 0) {
1325 return EFI_NOT_FOUND
;
1327 mPrivate
->ValidSinglePathCount
= mPrivate
->SinglePathCount
;
1335 Get the device path of the iSCSI tcp connection and update it.
1337 @param Session The iSCSI session.
1339 @return The updated device path.
1340 @retval NULL Other errors as indicated.
1343 EFI_DEVICE_PATH_PROTOCOL
*
1344 IScsiGetTcpConnDevicePath (
1345 IN ISCSI_SESSION
*Session
1348 ISCSI_CONNECTION
*Conn
;
1349 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1351 EFI_DEV_PATH
*DPathNode
;
1353 if (Session
->State
!= SESSION_STATE_LOGGED_IN
) {
1357 Conn
= NET_LIST_USER_STRUCT_S (
1358 Session
->Conns
.ForwardLink
,
1361 ISCSI_CONNECTION_SIGNATURE
1364 Status
= gBS
->HandleProtocol (
1366 &gEfiDevicePathProtocolGuid
,
1367 (VOID
**) &DevicePath
1369 if (EFI_ERROR (Status
)) {
1375 DevicePath
= DuplicateDevicePath (DevicePath
);
1376 if (DevicePath
== NULL
) {
1380 DPathNode
= (EFI_DEV_PATH
*) DevicePath
;
1382 while (!IsDevicePathEnd (&DPathNode
->DevPath
)) {
1383 if (DevicePathType (&DPathNode
->DevPath
) == MESSAGING_DEVICE_PATH
) {
1384 if (!Conn
->Ipv6Flag
&& DevicePathSubType (&DPathNode
->DevPath
) == MSG_IPv4_DP
) {
1385 DPathNode
->Ipv4
.LocalPort
= 0;
1387 DPathNode
->Ipv4
.StaticIpAddress
=
1388 (BOOLEAN
) (!Session
->ConfigData
->SessionConfigData
.InitiatorInfoFromDhcp
);
1391 &DPathNode
->Ipv4
.GatewayIpAddress
,
1392 &Session
->ConfigData
->SessionConfigData
.Gateway
1396 &DPathNode
->Ipv4
.SubnetMask
,
1397 &Session
->ConfigData
->SessionConfigData
.SubnetMask
1400 } else if (Conn
->Ipv6Flag
&& DevicePathSubType (&DPathNode
->DevPath
) == MSG_IPv6_DP
) {
1401 DPathNode
->Ipv6
.LocalPort
= 0;
1402 DPathNode
->Ipv6
.IpAddressOrigin
= 0;
1403 DPathNode
->Ipv6
.PrefixLength
= IP6_PREFIX_LENGTH
;
1404 ZeroMem (&DPathNode
->Ipv6
.GatewayIpAddress
, sizeof (EFI_IPv6_ADDRESS
));
1409 DPathNode
= (EFI_DEV_PATH
*) NextDevicePathNode (&DPathNode
->DevPath
);
1417 Abort the session when the transition from BS to RT is initiated.
1419 @param[in] Event The event signaled.
1420 @param[in] Context The iSCSI driver data.
1425 IScsiOnExitBootService (
1430 ISCSI_DRIVER_DATA
*Private
;
1432 Private
= (ISCSI_DRIVER_DATA
*) Context
;
1433 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
1435 if (Private
->Session
!= NULL
) {
1436 IScsiSessionAbort (Private
->Session
);
1441 Tests whether a controller handle is being managed by IScsi driver.
1443 This function tests whether the driver specified by DriverBindingHandle is
1444 currently managing the controller specified by ControllerHandle. This test
1445 is performed by evaluating if the the protocol specified by ProtocolGuid is
1446 present on ControllerHandle and is was opened by DriverBindingHandle and Nic
1447 Device handle with an attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
1448 If ProtocolGuid is NULL, then ASSERT().
1450 @param ControllerHandle A handle for a controller to test.
1451 @param DriverBindingHandle Specifies the driver binding handle for the
1453 @param ProtocolGuid Specifies the protocol that the driver specified
1454 by DriverBindingHandle opens in its Start()
1457 @retval EFI_SUCCESS ControllerHandle is managed by the driver
1458 specified by DriverBindingHandle.
1459 @retval EFI_UNSUPPORTED ControllerHandle is not managed by the driver
1460 specified by DriverBindingHandle.
1465 IScsiTestManagedDevice (
1466 IN EFI_HANDLE ControllerHandle
,
1467 IN EFI_HANDLE DriverBindingHandle
,
1468 IN EFI_GUID
*ProtocolGuid
1472 VOID
*ManagedInterface
;
1473 EFI_HANDLE NicControllerHandle
;
1475 ASSERT (ProtocolGuid
!= NULL
);
1477 NicControllerHandle
= NetLibGetNicHandle (ControllerHandle
, ProtocolGuid
);
1478 if (NicControllerHandle
== NULL
) {
1479 return EFI_UNSUPPORTED
;
1482 Status
= gBS
->OpenProtocol (
1484 (EFI_GUID
*) ProtocolGuid
,
1486 DriverBindingHandle
,
1487 NicControllerHandle
,
1488 EFI_OPEN_PROTOCOL_BY_DRIVER
1490 if (!EFI_ERROR (Status
)) {
1491 gBS
->CloseProtocol (
1493 (EFI_GUID
*) ProtocolGuid
,
1494 DriverBindingHandle
,
1497 return EFI_UNSUPPORTED
;
1500 if (Status
!= EFI_ALREADY_STARTED
) {
1501 return EFI_UNSUPPORTED
;