2 Miscellaneous routines for iSCSI driver.
4 Copyright (c) 2004 - 2016, 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 ASSERT (StrLen(Str
) >= 1);
230 Str
[StrLen (Str
) - 1] = 0;
232 for (Index
= StrLen (Str
) - 1; Index
> 1; Index
= Index
- 2) {
233 if ((Str
[Index
] == L
'0') && (Str
[Index
- 1] == L
'-')) {
242 Convert the formatted IP address into the binary IP address.
244 @param[in] Str The UNICODE string.
245 @param[in] IpMode Indicates whether the IP address is v4 or v6.
246 @param[out] Ip The storage to return the ASCII string.
248 @retval EFI_SUCCESS The binary IP address is returned in Ip.
249 @retval EFI_INVALID_PARAMETER The IP string is malformatted or IpMode is
257 OUT EFI_IP_ADDRESS
*Ip
262 if (IpMode
== IP_MODE_IP4
|| IpMode
== IP_MODE_AUTOCONFIG_IP4
) {
263 return NetLibAsciiStrToIp4 (Str
, &Ip
->v4
);
265 } else if (IpMode
== IP_MODE_IP6
|| IpMode
== IP_MODE_AUTOCONFIG_IP6
) {
266 return NetLibAsciiStrToIp6 (Str
, &Ip
->v6
);
268 } else if (IpMode
== IP_MODE_AUTOCONFIG
) {
269 Status
= NetLibAsciiStrToIp4 (Str
, &Ip
->v4
);
270 if (!EFI_ERROR (Status
)) {
273 return NetLibAsciiStrToIp6 (Str
, &Ip
->v6
);
277 return EFI_INVALID_PARAMETER
;
281 Convert the mac address into a hexadecimal encoded "-" seperated string.
283 @param[in] Mac The mac address.
284 @param[in] Len Length in bytes of the mac address.
285 @param[in] VlanId VLAN ID of the network device.
286 @param[out] Str The storage to return the mac string.
291 IN EFI_MAC_ADDRESS
*Mac
,
300 for (Index
= 0; Index
< Len
; Index
++) {
301 Str
[3 * Index
] = (CHAR16
) IScsiHexString
[(Mac
->Addr
[Index
] >> 4) & 0x0F];
302 Str
[3 * Index
+ 1] = (CHAR16
) IScsiHexString
[Mac
->Addr
[Index
] & 0x0F];
303 Str
[3 * Index
+ 2] = L
':';
306 String
= &Str
[3 * Index
- 1] ;
308 String
+= UnicodeSPrint (String
, 6 * sizeof (CHAR16
), L
"\\%04x", (UINTN
) VlanId
);
315 Convert the binary encoded buffer into a hexadecimal encoded string.
317 @param[in] BinBuffer The buffer containing the binary data.
318 @param[in] BinLength Length of the binary buffer.
319 @param[in, out] HexStr Pointer to the string.
320 @param[in, out] HexLength The length of the string.
322 @retval EFI_SUCCESS The binary data is converted to the hexadecimal string
323 and the length of the string is updated.
324 @retval EFI_BUFFER_TOO_SMALL The string is too small.
325 @retval EFI_INVALID_PARAMETER The IP string is malformatted.
332 IN OUT CHAR8
*HexStr
,
333 IN OUT UINT32
*HexLength
338 if ((HexStr
== NULL
) || (BinBuffer
== NULL
) || (BinLength
== 0)) {
339 return EFI_INVALID_PARAMETER
;
342 if (((*HexLength
) - 3) < BinLength
* 2) {
343 *HexLength
= BinLength
* 2 + 3;
344 return EFI_BUFFER_TOO_SMALL
;
347 *HexLength
= BinLength
* 2 + 3;
349 // Prefix for Hex String.
354 for (Index
= 0; Index
< BinLength
; Index
++) {
355 HexStr
[Index
* 2 + 2] = IScsiHexString
[BinBuffer
[Index
] >> 4];
356 HexStr
[Index
* 2 + 3] = IScsiHexString
[BinBuffer
[Index
] & 0xf];
359 HexStr
[Index
* 2 + 2] = '\0';
366 Convert the hexadecimal string into a binary encoded buffer.
368 @param[in, out] BinBuffer The binary buffer.
369 @param[in, out] BinLength Length of the binary buffer.
370 @param[in] HexStr The hexadecimal string.
372 @retval EFI_SUCCESS The hexadecimal string is converted into a binary
374 @retval EFI_BUFFER_TOO_SMALL The binary buffer is too small to hold the converted data.
379 IN OUT UINT8
*BinBuffer
,
380 IN OUT UINT32
*BinLength
,
389 ZeroMem (TemStr
, sizeof (TemStr
));
392 // Find out how many hex characters the string has.
394 if ((HexStr
[0] == '0') && ((HexStr
[1] == 'x') || (HexStr
[1] == 'X'))) {
398 Length
= AsciiStrLen (HexStr
);
400 for (Index
= 0; Index
< Length
; Index
++) {
401 TemStr
[0] = HexStr
[Index
];
402 Digit
= (UINT8
) AsciiStrHexToUint64 (TemStr
);
403 if (Digit
== 0 && TemStr
[0] != '0') {
409 if ((Index
& 1) == 0) {
410 BinBuffer
[Index
/2] = Digit
;
412 BinBuffer
[Index
/2] = (UINT8
) ((BinBuffer
[Index
/2] << 4) + Digit
);
416 *BinLength
= (UINT32
) ((Index
+ 1)/2);
423 Convert the decimal-constant string or hex-constant string into a numerical value.
425 @param[in] Str String in decimal or hex.
427 @return The numerical value.
435 if ((Str
[0] == '0') && ((Str
[1] == 'x') || (Str
[1] == 'X'))) {
438 return AsciiStrHexToUintn (Str
);
441 return AsciiStrDecimalToUintn (Str
);
446 Generate random numbers.
448 @param[in, out] Rand The buffer to contain random numbers.
449 @param[in] RandLength The length of the Rand buffer.
460 while (RandLength
> 0) {
461 Random
= NET_RANDOM (NetRandomInitSeed ());
462 *Rand
++ = (UINT8
) (Random
);
469 Record the NIC info in global structure.
471 @param[in] Controller The handle of the controller.
473 @retval EFI_SUCCESS The operation is completed.
474 @retval EFI_OUT_OF_RESOURCES Do not have sufficient resources to finish this
480 IN EFI_HANDLE Controller
484 ISCSI_NIC_INFO
*NicInfo
;
486 EFI_MAC_ADDRESS MacAddr
;
491 // Get MAC address of this network device.
493 Status
= NetLibGetMacAddress (Controller
, &MacAddr
, &HwAddressSize
);
494 if (EFI_ERROR (Status
)) {
499 // Get VLAN ID of this network device.
501 VlanId
= NetLibGetVlanId (Controller
);
504 // Check whether the NIC info already exists. Return directly if so.
506 NET_LIST_FOR_EACH (Entry
, &mPrivate
->NicInfoList
) {
507 NicInfo
= NET_LIST_USER_STRUCT (Entry
, ISCSI_NIC_INFO
, Link
);
508 if (NicInfo
->HwAddressSize
== HwAddressSize
&&
509 CompareMem (&NicInfo
->PermanentAddress
, MacAddr
.Addr
, HwAddressSize
) == 0 &&
510 NicInfo
->VlanId
== VlanId
) {
511 mPrivate
->CurrentNic
= NicInfo
->NicIndex
;
515 if (mPrivate
->MaxNic
< NicInfo
->NicIndex
) {
516 mPrivate
->MaxNic
= NicInfo
->NicIndex
;
521 // Record the NIC info in private structure.
523 NicInfo
= AllocateZeroPool (sizeof (ISCSI_NIC_INFO
));
524 if (NicInfo
== NULL
) {
525 return EFI_OUT_OF_RESOURCES
;
528 CopyMem (&NicInfo
->PermanentAddress
, MacAddr
.Addr
, HwAddressSize
);
529 NicInfo
->HwAddressSize
= (UINT32
) HwAddressSize
;
530 NicInfo
->VlanId
= VlanId
;
531 NicInfo
->NicIndex
= (UINT8
) (mPrivate
->MaxNic
+ 1);
532 mPrivate
->MaxNic
= NicInfo
->NicIndex
;
535 // Get the PCI location.
537 IScsiGetNICPciLocation (
540 &NicInfo
->DeviceNumber
,
541 &NicInfo
->FunctionNumber
544 InsertTailList (&mPrivate
->NicInfoList
, &NicInfo
->Link
);
545 mPrivate
->NicCount
++;
547 mPrivate
->CurrentNic
= NicInfo
->NicIndex
;
553 Delete the recorded NIC info from global structure. Also delete corresponding
556 @param[in] Controller The handle of the controller.
558 @retval EFI_SUCCESS The operation is completed.
559 @retval EFI_NOT_FOUND The NIC info to be deleted is not recorded.
564 IN EFI_HANDLE Controller
568 ISCSI_NIC_INFO
*NicInfo
;
570 LIST_ENTRY
*NextEntry
;
571 ISCSI_ATTEMPT_CONFIG_NVDATA
*AttemptConfigData
;
572 ISCSI_NIC_INFO
*ThisNic
;
573 EFI_MAC_ADDRESS MacAddr
;
578 // Get MAC address of this network device.
580 Status
= NetLibGetMacAddress (Controller
, &MacAddr
, &HwAddressSize
);
581 if (EFI_ERROR (Status
)) {
586 // Get VLAN ID of this network device.
588 VlanId
= NetLibGetVlanId (Controller
);
591 // Check whether the NIC information exists.
595 NET_LIST_FOR_EACH (Entry
, &mPrivate
->NicInfoList
) {
596 NicInfo
= NET_LIST_USER_STRUCT (Entry
, ISCSI_NIC_INFO
, Link
);
597 if (NicInfo
->HwAddressSize
== HwAddressSize
&&
598 CompareMem (&NicInfo
->PermanentAddress
, MacAddr
.Addr
, HwAddressSize
) == 0 &&
599 NicInfo
->VlanId
== VlanId
) {
606 if (ThisNic
== NULL
) {
607 return EFI_NOT_FOUND
;
610 mPrivate
->CurrentNic
= ThisNic
->NicIndex
;
612 RemoveEntryList (&ThisNic
->Link
);
614 mPrivate
->NicCount
--;
617 // Remove all attempts related to this NIC.
619 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &mPrivate
->AttemptConfigs
) {
620 AttemptConfigData
= NET_LIST_USER_STRUCT (Entry
, ISCSI_ATTEMPT_CONFIG_NVDATA
, Link
);
621 if (AttemptConfigData
->NicIndex
== mPrivate
->CurrentNic
) {
622 RemoveEntryList (&AttemptConfigData
->Link
);
623 mPrivate
->AttemptCount
--;
625 if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED_FOR_MPIO
&& mPrivate
->MpioCount
> 0) {
626 if (--mPrivate
->MpioCount
== 0) {
627 mPrivate
->EnableMpio
= FALSE
;
630 if (AttemptConfigData
->AuthenticationType
== ISCSI_AUTH_TYPE_KRB
&& mPrivate
->Krb5MpioCount
> 0) {
631 mPrivate
->Krb5MpioCount
--;
634 } else if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED
&& mPrivate
->SinglePathCount
> 0) {
635 mPrivate
->SinglePathCount
--;
637 if (mPrivate
->ValidSinglePathCount
> 0) {
638 mPrivate
->ValidSinglePathCount
--;
642 FreePool (AttemptConfigData
);
647 // Free attempt is created but not saved to system.
649 if (mPrivate
->NewAttempt
!= NULL
) {
650 FreePool (mPrivate
->NewAttempt
);
651 mPrivate
->NewAttempt
= NULL
;
659 Get the recorded NIC info from global structure by the Index.
661 @param[in] NicIndex The index indicates the position of NIC info.
663 @return Pointer to the NIC info, or NULL if not found.
667 IScsiGetNicInfoByIndex (
672 ISCSI_NIC_INFO
*NicInfo
;
674 NET_LIST_FOR_EACH (Entry
, &mPrivate
->NicInfoList
) {
675 NicInfo
= NET_LIST_USER_STRUCT (Entry
, ISCSI_NIC_INFO
, Link
);
676 if (NicInfo
->NicIndex
== NicIndex
) {
686 Get the NIC's PCI location and return it according to the composited
687 format defined in iSCSI Boot Firmware Table.
689 @param[in] Controller The handle of the controller.
690 @param[out] Bus The bus number.
691 @param[out] Device The device number.
692 @param[out] Function The function number.
694 @return The composited representation of the NIC PCI location.
698 IScsiGetNICPciLocation (
699 IN EFI_HANDLE Controller
,
706 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
707 EFI_HANDLE PciIoHandle
;
708 EFI_PCI_IO_PROTOCOL
*PciIo
;
711 Status
= gBS
->HandleProtocol (
713 &gEfiDevicePathProtocolGuid
,
714 (VOID
**) &DevicePath
716 if (EFI_ERROR (Status
)) {
720 Status
= gBS
->LocateDevicePath (
721 &gEfiPciIoProtocolGuid
,
725 if (EFI_ERROR (Status
)) {
729 Status
= gBS
->HandleProtocol (PciIoHandle
, &gEfiPciIoProtocolGuid
, (VOID
**) &PciIo
);
730 if (EFI_ERROR (Status
)) {
734 Status
= PciIo
->GetLocation (PciIo
, &Segment
, Bus
, Device
, Function
);
735 if (EFI_ERROR (Status
)) {
739 return (UINT16
) ((*Bus
<< 8) | (*Device
<< 3) | *Function
);
744 Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
745 buffer, and the size of the buffer. If failure, return NULL.
747 @param[in] Name String part of EFI variable name.
748 @param[in] VendorGuid GUID part of EFI variable name.
749 @param[out] VariableSize Returns the size of the EFI variable that was read.
751 @return Dynamically allocated memory that contains a copy of the EFI variable.
752 @return Caller is responsible freeing the buffer.
753 @retval NULL Variable was not read.
757 IScsiGetVariableAndSize (
759 IN EFI_GUID
*VendorGuid
,
760 OUT UINTN
*VariableSize
770 // Pass in a zero size buffer to find the required buffer size.
773 Status
= gRT
->GetVariable (Name
, VendorGuid
, NULL
, &BufferSize
, Buffer
);
774 if (Status
== EFI_BUFFER_TOO_SMALL
) {
776 // Allocate the buffer to return
778 Buffer
= AllocateZeroPool (BufferSize
);
779 if (Buffer
== NULL
) {
783 // Read variable into the allocated buffer.
785 Status
= gRT
->GetVariable (Name
, VendorGuid
, NULL
, &BufferSize
, Buffer
);
786 if (EFI_ERROR (Status
)) {
791 *VariableSize
= BufferSize
;
797 Create the iSCSI driver data.
799 @param[in] Image The handle of the driver image.
800 @param[in] Controller The handle of the controller.
802 @return The iSCSI driver data created.
803 @retval NULL Other errors as indicated.
807 IScsiCreateDriverData (
809 IN EFI_HANDLE Controller
812 ISCSI_DRIVER_DATA
*Private
;
815 Private
= AllocateZeroPool (sizeof (ISCSI_DRIVER_DATA
));
816 if (Private
== NULL
) {
820 Private
->Signature
= ISCSI_DRIVER_DATA_SIGNATURE
;
821 Private
->Image
= Image
;
822 Private
->Controller
= Controller
;
823 Private
->Session
= NULL
;
826 // Create an event to be signaled when the BS to RT transition is triggerd so
827 // as to abort the iSCSI session.
829 Status
= gBS
->CreateEventEx (
832 IScsiOnExitBootService
,
834 &gEfiEventExitBootServicesGuid
,
835 &Private
->ExitBootServiceEvent
837 if (EFI_ERROR (Status
)) {
842 Private
->ExtScsiPassThruHandle
= NULL
;
843 CopyMem(&Private
->IScsiExtScsiPassThru
, &gIScsiExtScsiPassThruProtocolTemplate
, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL
));
846 // 0 is designated to the TargetId, so use another value for the AdapterId.
848 Private
->ExtScsiPassThruMode
.AdapterId
= 2;
849 Private
->ExtScsiPassThruMode
.Attributes
= EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
| EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
850 Private
->ExtScsiPassThruMode
.IoAlign
= 4;
851 Private
->IScsiExtScsiPassThru
.Mode
= &Private
->ExtScsiPassThruMode
;
858 Clean the iSCSI driver data.
860 @param[in] Private The iSCSI driver data.
862 @retval EFI_SUCCESS The clean operation is successful.
863 @retval Others Other errors as indicated.
867 IScsiCleanDriverData (
868 IN ISCSI_DRIVER_DATA
*Private
873 Status
= EFI_SUCCESS
;
875 if (Private
->DevicePath
!= NULL
) {
876 Status
= gBS
->UninstallProtocolInterface (
877 Private
->ExtScsiPassThruHandle
,
878 &gEfiDevicePathProtocolGuid
,
881 if (EFI_ERROR (Status
)) {
885 FreePool (Private
->DevicePath
);
888 if (Private
->ExtScsiPassThruHandle
!= NULL
) {
889 Status
= gBS
->UninstallProtocolInterface (
890 Private
->ExtScsiPassThruHandle
,
891 &gEfiExtScsiPassThruProtocolGuid
,
892 &Private
->IScsiExtScsiPassThru
894 if (!EFI_ERROR (Status
)) {
895 mPrivate
->OneSessionEstablished
= FALSE
;
901 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
903 mCallbackInfo
->Current
= NULL
;
910 Check wheather the Controller handle is configured to use DHCP protocol.
912 @param[in] Controller The handle of the controller.
913 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
915 @retval TRUE The handle of the controller need the Dhcp protocol.
916 @retval FALSE The handle of the controller does not need the Dhcp protocol.
920 IScsiDhcpIsConfigured (
921 IN EFI_HANDLE Controller
,
925 ISCSI_ATTEMPT_CONFIG_NVDATA
*AttemptTmp
;
926 UINT8
*AttemptConfigOrder
;
927 UINTN AttemptConfigOrderSize
;
930 EFI_MAC_ADDRESS MacAddr
;
933 CHAR16 MacString
[ISCSI_MAX_MAC_STRING_LEN
];
934 CHAR16 AttemptName
[ISCSI_NAME_IFR_MAX_SIZE
];
936 AttemptConfigOrder
= IScsiGetVariableAndSize (
939 &AttemptConfigOrderSize
941 if (AttemptConfigOrder
== NULL
|| AttemptConfigOrderSize
== 0) {
946 // Get MAC address of this network device.
948 Status
= NetLibGetMacAddress (Controller
, &MacAddr
, &HwAddressSize
);
949 if(EFI_ERROR (Status
)) {
953 // Get VLAN ID of this network device.
955 VlanId
= NetLibGetVlanId (Controller
);
956 IScsiMacAddrToStr (&MacAddr
, (UINT32
) HwAddressSize
, VlanId
, MacString
);
958 for (Index
= 0; Index
< AttemptConfigOrderSize
/ sizeof (UINT8
); Index
++) {
964 (UINTN
) AttemptConfigOrder
[Index
]
966 Status
= GetVariable2 (
968 &gEfiIScsiInitiatorNameProtocolGuid
,
972 if(AttemptTmp
== NULL
|| EFI_ERROR (Status
)) {
976 ASSERT (AttemptConfigOrder
[Index
] == AttemptTmp
->AttemptConfigIndex
);
978 if (AttemptTmp
->SessionConfigData
.Enabled
== ISCSI_DISABLED
) {
979 FreePool (AttemptTmp
);
983 if (AttemptTmp
->SessionConfigData
.IpMode
!= IP_MODE_AUTOCONFIG
&&
984 AttemptTmp
->SessionConfigData
.IpMode
!= ((IpVersion
== IP_VERSION_4
) ? IP_MODE_IP4
: IP_MODE_IP6
)) {
985 FreePool (AttemptTmp
);
989 if(AttemptTmp
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
||
990 AttemptTmp
->SessionConfigData
.InitiatorInfoFromDhcp
== TRUE
||
991 AttemptTmp
->SessionConfigData
.TargetInfoFromDhcp
== TRUE
) {
992 FreePool (AttemptTmp
);
993 FreePool (AttemptConfigOrder
);
997 FreePool (AttemptTmp
);
1000 FreePool (AttemptConfigOrder
);
1005 Get the various configuration data.
1007 @param[in] Private The iSCSI driver data.
1009 @retval EFI_SUCCESS The configuration data is retrieved.
1010 @retval EFI_NOT_FOUND This iSCSI driver is not configured yet.
1011 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1015 IScsiGetConfigData (
1016 IN ISCSI_DRIVER_DATA
*Private
1020 CHAR16 MacString
[ISCSI_MAX_MAC_STRING_LEN
];
1022 ISCSI_NIC_INFO
*NicInfo
;
1023 ISCSI_ATTEMPT_CONFIG_NVDATA
*AttemptConfigData
;
1024 ISCSI_ATTEMPT_CONFIG_NVDATA
*AttemptTmp
;
1025 UINT8
*AttemptConfigOrder
;
1026 UINTN AttemptConfigOrderSize
;
1027 CHAR16 IScsiMode
[64];
1031 // There should be at least one attempt configured.
1033 AttemptConfigOrder
= IScsiGetVariableAndSize (
1036 &AttemptConfigOrderSize
1038 if (AttemptConfigOrder
== NULL
|| AttemptConfigOrderSize
== 0) {
1039 return EFI_NOT_FOUND
;
1043 // Get the iSCSI Initiator Name.
1045 mPrivate
->InitiatorNameLength
= ISCSI_NAME_MAX_SIZE
;
1046 Status
= gIScsiInitiatorName
.Get (
1047 &gIScsiInitiatorName
,
1048 &mPrivate
->InitiatorNameLength
,
1049 mPrivate
->InitiatorName
1051 if (EFI_ERROR (Status
)) {
1056 // Get the normal configuration.
1058 for (Index
= 0; Index
< AttemptConfigOrderSize
/ sizeof (UINT8
); Index
++) {
1061 // Check whether the attempt exists in AttemptConfig.
1063 AttemptTmp
= IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder
[Index
]);
1064 if (AttemptTmp
!= NULL
&& AttemptTmp
->SessionConfigData
.Enabled
== ISCSI_DISABLED
) {
1066 } else if (AttemptTmp
!= NULL
&& AttemptTmp
->SessionConfigData
.Enabled
!= ISCSI_DISABLED
) {
1068 // Check the autoconfig path to see whether it should be retried.
1070 if (AttemptTmp
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
&&
1071 !AttemptTmp
->AutoConfigureSuccess
) {
1072 if (mPrivate
->Ipv6Flag
&&
1073 AttemptTmp
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP6
) {
1075 // Autoconfigure for IP6 already attempted but failed. Do not try again.
1078 } else if (!mPrivate
->Ipv6Flag
&&
1079 AttemptTmp
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP4
) {
1081 // Autoconfigure for IP4 already attempted but failed. Do not try again.
1086 // Try another approach for this autoconfigure path.
1088 AttemptTmp
->AutoConfigureMode
=
1089 (UINT8
) (mPrivate
->Ipv6Flag
? IP_MODE_AUTOCONFIG_IP6
: IP_MODE_AUTOCONFIG_IP4
);
1090 AttemptTmp
->SessionConfigData
.InitiatorInfoFromDhcp
= TRUE
;
1091 AttemptTmp
->SessionConfigData
.TargetInfoFromDhcp
= TRUE
;
1092 AttemptTmp
->DhcpSuccess
= FALSE
;
1095 // Get some information from the dhcp server.
1097 if (!mPrivate
->Ipv6Flag
) {
1098 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, AttemptTmp
);
1099 if (!EFI_ERROR (Status
)) {
1100 AttemptTmp
->DhcpSuccess
= TRUE
;
1103 Status
= IScsiDoDhcp6 (Private
->Image
, Private
->Controller
, AttemptTmp
);
1104 if (!EFI_ERROR (Status
)) {
1105 AttemptTmp
->DhcpSuccess
= TRUE
;
1110 // Refresh the state of this attempt to NVR.
1112 AsciiStrToUnicodeStrS (AttemptTmp
->MacString
, MacString
, sizeof (MacString
) / sizeof (MacString
[0]));
1114 mPrivate
->PortString
,
1115 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
1118 (UINTN
) AttemptTmp
->AttemptConfigIndex
1122 mPrivate
->PortString
,
1123 &gEfiIScsiInitiatorNameProtocolGuid
,
1124 ISCSI_CONFIG_VAR_ATTR
,
1125 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA
),
1131 } else if (AttemptTmp
->SessionConfigData
.InitiatorInfoFromDhcp
&& !AttemptTmp
->ValidPath
) {
1133 // Get DHCP information for already added, but failed, attempt.
1135 AttemptTmp
->DhcpSuccess
= FALSE
;
1136 if (!mPrivate
->Ipv6Flag
&& (AttemptTmp
->SessionConfigData
.IpMode
== IP_MODE_IP4
)) {
1137 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, AttemptTmp
);
1138 if (!EFI_ERROR (Status
)) {
1139 AttemptTmp
->DhcpSuccess
= TRUE
;
1141 } else if (mPrivate
->Ipv6Flag
&& (AttemptTmp
->SessionConfigData
.IpMode
== IP_MODE_IP6
)) {
1142 Status
= IScsiDoDhcp6 (Private
->Image
, Private
->Controller
, AttemptTmp
);
1143 if (!EFI_ERROR (Status
)) {
1144 AttemptTmp
->DhcpSuccess
= TRUE
;
1149 // Refresh the state of this attempt to NVR.
1151 AsciiStrToUnicodeStrS (AttemptTmp
->MacString
, MacString
, sizeof (MacString
) / sizeof (MacString
[0]));
1153 mPrivate
->PortString
,
1154 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
1157 (UINTN
) AttemptTmp
->AttemptConfigIndex
1161 mPrivate
->PortString
,
1162 &gEfiIScsiInitiatorNameProtocolGuid
,
1163 ISCSI_CONFIG_VAR_ATTR
,
1164 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA
),
1176 // This attempt does not exist in AttemptConfig. Try to add a new one.
1179 NicInfo
= IScsiGetNicInfoByIndex (mPrivate
->CurrentNic
);
1180 ASSERT (NicInfo
!= NULL
);
1181 IScsiMacAddrToStr (&NicInfo
->PermanentAddress
, NicInfo
->HwAddressSize
, NicInfo
->VlanId
, MacString
);
1183 mPrivate
->PortString
,
1187 (UINTN
) AttemptConfigOrder
[Index
]
1191 mPrivate
->PortString
,
1192 &gEfiIScsiInitiatorNameProtocolGuid
,
1193 (VOID
**)&AttemptConfigData
,
1197 if (AttemptConfigData
== NULL
) {
1201 ASSERT (AttemptConfigOrder
[Index
] == AttemptConfigData
->AttemptConfigIndex
);
1203 AttemptConfigData
->NicIndex
= NicInfo
->NicIndex
;
1204 AttemptConfigData
->DhcpSuccess
= FALSE
;
1205 AttemptConfigData
->ValidiBFTPath
= (BOOLEAN
) (mPrivate
->EnableMpio
? TRUE
: FALSE
);
1206 AttemptConfigData
->ValidPath
= FALSE
;
1208 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
) {
1209 AttemptConfigData
->SessionConfigData
.InitiatorInfoFromDhcp
= TRUE
;
1210 AttemptConfigData
->SessionConfigData
.TargetInfoFromDhcp
= TRUE
;
1212 AttemptConfigData
->AutoConfigureMode
=
1213 (UINT8
) (mPrivate
->Ipv6Flag
? IP_MODE_AUTOCONFIG_IP6
: IP_MODE_AUTOCONFIG_IP4
);
1214 AttemptConfigData
->AutoConfigureSuccess
= FALSE
;
1218 // Get some information from dhcp server.
1220 if (AttemptConfigData
->SessionConfigData
.Enabled
!= ISCSI_DISABLED
&&
1221 AttemptConfigData
->SessionConfigData
.InitiatorInfoFromDhcp
) {
1223 if (!mPrivate
->Ipv6Flag
&&
1224 (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP4
||
1225 AttemptConfigData
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP4
)) {
1226 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, AttemptConfigData
);
1227 if (!EFI_ERROR (Status
)) {
1228 AttemptConfigData
->DhcpSuccess
= TRUE
;
1230 } else if (mPrivate
->Ipv6Flag
&&
1231 (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP6
||
1232 AttemptConfigData
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP6
)) {
1233 Status
= IScsiDoDhcp6 (Private
->Image
, Private
->Controller
, AttemptConfigData
);
1234 if (!EFI_ERROR (Status
)) {
1235 AttemptConfigData
->DhcpSuccess
= TRUE
;
1240 // Refresh the state of this attempt to NVR.
1242 AsciiStrToUnicodeStrS (AttemptConfigData
->MacString
, MacString
, sizeof (MacString
) / sizeof (MacString
[0]));
1244 mPrivate
->PortString
,
1245 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
1248 (UINTN
) AttemptConfigData
->AttemptConfigIndex
1252 mPrivate
->PortString
,
1253 &gEfiIScsiInitiatorNameProtocolGuid
,
1254 ISCSI_CONFIG_VAR_ATTR
,
1255 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA
),
1261 // Update Attempt Help Info.
1264 if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_DISABLED
) {
1265 UnicodeSPrint (IScsiMode
, 64, L
"Disabled");
1266 } else if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED
) {
1267 UnicodeSPrint (IScsiMode
, 64, L
"Enabled");
1268 } else if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED_FOR_MPIO
) {
1269 UnicodeSPrint (IScsiMode
, 64, L
"Enabled for MPIO");
1272 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP4
) {
1273 UnicodeSPrint (IpMode
, 64, L
"IP4");
1274 } else if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP6
) {
1275 UnicodeSPrint (IpMode
, 64, L
"IP6");
1276 } else if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
) {
1277 UnicodeSPrint (IpMode
, 64, L
"Autoconfigure");
1281 mPrivate
->PortString
,
1282 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
1283 L
"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s",
1286 NicInfo
->DeviceNumber
,
1287 NicInfo
->FunctionNumber
,
1292 AttemptConfigData
->AttemptTitleHelpToken
= HiiSetString (
1293 mCallbackInfo
->RegisteredHandle
,
1295 mPrivate
->PortString
,
1298 if (AttemptConfigData
->AttemptTitleHelpToken
== 0) {
1299 return EFI_OUT_OF_RESOURCES
;
1303 // Record the attempt in global link list.
1305 InsertTailList (&mPrivate
->AttemptConfigs
, &AttemptConfigData
->Link
);
1306 mPrivate
->AttemptCount
++;
1308 if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED_FOR_MPIO
) {
1309 mPrivate
->MpioCount
++;
1310 mPrivate
->EnableMpio
= TRUE
;
1312 if (AttemptConfigData
->AuthenticationType
== ISCSI_AUTH_TYPE_KRB
) {
1313 mPrivate
->Krb5MpioCount
++;
1315 } else if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED
) {
1316 mPrivate
->SinglePathCount
++;
1321 // Reorder the AttemptConfig by the configured order.
1323 for (Index
= 0; Index
< AttemptConfigOrderSize
/ sizeof (UINT8
); Index
++) {
1324 AttemptConfigData
= IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder
[Index
]);
1325 if (AttemptConfigData
== NULL
) {
1329 RemoveEntryList (&AttemptConfigData
->Link
);
1330 InsertTailList (&mPrivate
->AttemptConfigs
, &AttemptConfigData
->Link
);
1334 // Update the Main Form.
1336 IScsiConfigUpdateAttempt ();
1338 FreePool (AttemptConfigOrder
);
1341 // There should be at least one attempt configuration.
1343 if (!mPrivate
->EnableMpio
) {
1344 if (mPrivate
->SinglePathCount
== 0) {
1345 return EFI_NOT_FOUND
;
1347 mPrivate
->ValidSinglePathCount
= mPrivate
->SinglePathCount
;
1355 Get the device path of the iSCSI tcp connection and update it.
1357 @param Session The iSCSI session.
1359 @return The updated device path.
1360 @retval NULL Other errors as indicated.
1363 EFI_DEVICE_PATH_PROTOCOL
*
1364 IScsiGetTcpConnDevicePath (
1365 IN ISCSI_SESSION
*Session
1368 ISCSI_CONNECTION
*Conn
;
1369 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1371 EFI_DEV_PATH
*DPathNode
;
1374 if (Session
->State
!= SESSION_STATE_LOGGED_IN
) {
1378 Conn
= NET_LIST_USER_STRUCT_S (
1379 Session
->Conns
.ForwardLink
,
1382 ISCSI_CONNECTION_SIGNATURE
1385 Status
= gBS
->HandleProtocol (
1387 &gEfiDevicePathProtocolGuid
,
1388 (VOID
**) &DevicePath
1390 if (EFI_ERROR (Status
)) {
1396 DevicePath
= DuplicateDevicePath (DevicePath
);
1397 if (DevicePath
== NULL
) {
1401 DPathNode
= (EFI_DEV_PATH
*) DevicePath
;
1403 while (!IsDevicePathEnd (&DPathNode
->DevPath
)) {
1404 if (DevicePathType (&DPathNode
->DevPath
) == MESSAGING_DEVICE_PATH
) {
1405 if (!Conn
->Ipv6Flag
&& DevicePathSubType (&DPathNode
->DevPath
) == MSG_IPv4_DP
) {
1406 DPathNode
->Ipv4
.LocalPort
= 0;
1408 DPathNode
->Ipv4
.StaticIpAddress
=
1409 (BOOLEAN
) (!Session
->ConfigData
->SessionConfigData
.InitiatorInfoFromDhcp
);
1412 // Add a judgement here to support previous versions of IPv4_DEVICE_PATH.
1413 // In previous versions of IPv4_DEVICE_PATH, GatewayIpAddress and SubnetMask
1415 // In new version of IPv4_DEVICE_PATH, structcure length is 27.
1418 PathLen
= DevicePathNodeLength (&DPathNode
->Ipv4
);
1420 if (PathLen
== IP4_NODE_LEN_NEW_VERSIONS
) {
1423 &DPathNode
->Ipv4
.GatewayIpAddress
,
1424 &Session
->ConfigData
->SessionConfigData
.Gateway
1428 &DPathNode
->Ipv4
.SubnetMask
,
1429 &Session
->ConfigData
->SessionConfigData
.SubnetMask
1434 } else if (Conn
->Ipv6Flag
&& DevicePathSubType (&DPathNode
->DevPath
) == MSG_IPv6_DP
) {
1435 DPathNode
->Ipv6
.LocalPort
= 0;
1438 // Add a judgement here to support previous versions of IPv6_DEVICE_PATH.
1439 // In previous versions of IPv6_DEVICE_PATH, IpAddressOrigin, PrefixLength
1440 // and GatewayIpAddress do not exist.
1441 // In new version of IPv6_DEVICE_PATH, structure length is 60, while in
1442 // old versions, the length is 43.
1445 PathLen
= DevicePathNodeLength (&DPathNode
->Ipv6
);
1447 if (PathLen
== IP6_NODE_LEN_NEW_VERSIONS
) {
1449 DPathNode
->Ipv6
.IpAddressOrigin
= 0;
1450 DPathNode
->Ipv6
.PrefixLength
= IP6_PREFIX_LENGTH
;
1451 ZeroMem (&DPathNode
->Ipv6
.GatewayIpAddress
, sizeof (EFI_IPv6_ADDRESS
));
1453 else if (PathLen
== IP6_NODE_LEN_OLD_VERSIONS
) {
1456 // StaticIPAddress is a field in old versions of IPv6_DEVICE_PATH, while ignored in new
1457 // version. Set StaticIPAddress through its' offset in old IPv6_DEVICE_PATH.
1459 *((UINT8
*)(&DPathNode
->Ipv6
) + IP6_OLD_IPADDRESS_OFFSET
) =
1460 (BOOLEAN
) (!Session
->ConfigData
->SessionConfigData
.InitiatorInfoFromDhcp
);
1467 DPathNode
= (EFI_DEV_PATH
*) NextDevicePathNode (&DPathNode
->DevPath
);
1475 Abort the session when the transition from BS to RT is initiated.
1477 @param[in] Event The event signaled.
1478 @param[in] Context The iSCSI driver data.
1483 IScsiOnExitBootService (
1488 ISCSI_DRIVER_DATA
*Private
;
1490 Private
= (ISCSI_DRIVER_DATA
*) Context
;
1491 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
1493 if (Private
->Session
!= NULL
) {
1494 IScsiSessionAbort (Private
->Session
);
1499 Tests whether a controller handle is being managed by IScsi driver.
1501 This function tests whether the driver specified by DriverBindingHandle is
1502 currently managing the controller specified by ControllerHandle. This test
1503 is performed by evaluating if the the protocol specified by ProtocolGuid is
1504 present on ControllerHandle and is was opened by DriverBindingHandle and Nic
1505 Device handle with an attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
1506 If ProtocolGuid is NULL, then ASSERT().
1508 @param ControllerHandle A handle for a controller to test.
1509 @param DriverBindingHandle Specifies the driver binding handle for the
1511 @param ProtocolGuid Specifies the protocol that the driver specified
1512 by DriverBindingHandle opens in its Start()
1515 @retval EFI_SUCCESS ControllerHandle is managed by the driver
1516 specified by DriverBindingHandle.
1517 @retval EFI_UNSUPPORTED ControllerHandle is not managed by the driver
1518 specified by DriverBindingHandle.
1523 IScsiTestManagedDevice (
1524 IN EFI_HANDLE ControllerHandle
,
1525 IN EFI_HANDLE DriverBindingHandle
,
1526 IN EFI_GUID
*ProtocolGuid
1530 VOID
*ManagedInterface
;
1531 EFI_HANDLE NicControllerHandle
;
1533 ASSERT (ProtocolGuid
!= NULL
);
1535 NicControllerHandle
= NetLibGetNicHandle (ControllerHandle
, ProtocolGuid
);
1536 if (NicControllerHandle
== NULL
) {
1537 return EFI_UNSUPPORTED
;
1540 Status
= gBS
->OpenProtocol (
1542 (EFI_GUID
*) ProtocolGuid
,
1544 DriverBindingHandle
,
1545 NicControllerHandle
,
1546 EFI_OPEN_PROTOCOL_BY_DRIVER
1548 if (!EFI_ERROR (Status
)) {
1549 gBS
->CloseProtocol (
1551 (EFI_GUID
*) ProtocolGuid
,
1552 DriverBindingHandle
,
1555 return EFI_UNSUPPORTED
;
1558 if (Status
!= EFI_ALREADY_STARTED
) {
1559 return EFI_UNSUPPORTED
;