mirror of https://github.com/acidanthera/audk.git
1548 lines
44 KiB
C
1548 lines
44 KiB
C
/** @file
|
|
Miscellaneous routines for iSCSI driver.
|
|
|
|
Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
|
|
#include "IScsiImpl.h"
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 IScsiHexString[] = "0123456789ABCDEFabcdef";
|
|
|
|
/**
|
|
Removes (trims) specified leading and trailing characters from a string.
|
|
|
|
@param[in, out] Str Pointer to the null-terminated string to be trimmed.
|
|
On return, Str will hold the trimmed string.
|
|
|
|
@param[in] CharC Character will be trimmed from str.
|
|
|
|
**/
|
|
VOID
|
|
IScsiStrTrim (
|
|
IN OUT CHAR16 *Str,
|
|
IN CHAR16 CharC
|
|
)
|
|
{
|
|
CHAR16 *Pointer1;
|
|
CHAR16 *Pointer2;
|
|
|
|
if (*Str == 0) {
|
|
return ;
|
|
}
|
|
|
|
//
|
|
// Trim off the leading and trailing characters c
|
|
//
|
|
for (Pointer1 = Str; (*Pointer1 != 0) && (*Pointer1 == CharC); Pointer1++) {
|
|
;
|
|
}
|
|
|
|
Pointer2 = Str;
|
|
if (Pointer2 == Pointer1) {
|
|
while (*Pointer1 != 0) {
|
|
Pointer2++;
|
|
Pointer1++;
|
|
}
|
|
} else {
|
|
while (*Pointer1 != 0) {
|
|
*Pointer2 = *Pointer1;
|
|
Pointer1++;
|
|
Pointer2++;
|
|
}
|
|
*Pointer2 = 0;
|
|
}
|
|
|
|
|
|
for (Pointer1 = Str + StrLen(Str) - 1; Pointer1 >= Str && *Pointer1 == CharC; Pointer1--) {
|
|
;
|
|
}
|
|
if (Pointer1 != Str + StrLen(Str) - 1) {
|
|
*(Pointer1 + 1) = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Calculate the prefix length of the IPv4 subnet mask.
|
|
|
|
@param[in] SubnetMask The IPv4 subnet mask.
|
|
|
|
@return The prefix length of the subnet mask.
|
|
@retval 0 Other errors as indicated.
|
|
|
|
**/
|
|
UINT8
|
|
IScsiGetSubnetMaskPrefixLength (
|
|
IN EFI_IPv4_ADDRESS *SubnetMask
|
|
)
|
|
{
|
|
UINT8 Len;
|
|
UINT32 ReverseMask;
|
|
|
|
//
|
|
// The SubnetMask is in network byte order.
|
|
//
|
|
ReverseMask = (SubnetMask->Addr[0] << 24) | (SubnetMask->Addr[1] << 16) | (SubnetMask->Addr[2] << 8) | (SubnetMask->Addr[3]);
|
|
|
|
//
|
|
// Reverse it.
|
|
//
|
|
ReverseMask = ~ReverseMask;
|
|
|
|
if ((ReverseMask & (ReverseMask + 1)) != 0) {
|
|
return 0;
|
|
}
|
|
|
|
Len = 0;
|
|
|
|
while (ReverseMask != 0) {
|
|
ReverseMask = ReverseMask >> 1;
|
|
Len++;
|
|
}
|
|
|
|
return (UINT8) (32 - Len);
|
|
}
|
|
|
|
|
|
/**
|
|
Convert the hexadecimal encoded LUN string into the 64-bit LUN.
|
|
|
|
@param[in] Str The hexadecimal encoded LUN string.
|
|
@param[out] Lun Storage to return the 64-bit LUN.
|
|
|
|
@retval EFI_SUCCESS The 64-bit LUN is stored in Lun.
|
|
@retval EFI_INVALID_PARAMETER The string is malformatted.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
IScsiAsciiStrToLun (
|
|
IN CHAR8 *Str,
|
|
OUT UINT8 *Lun
|
|
)
|
|
{
|
|
UINTN Index, IndexValue, IndexNum, SizeStr;
|
|
CHAR8 TemStr[2];
|
|
UINT8 TemValue;
|
|
UINT16 Value[4];
|
|
|
|
ZeroMem (Lun, 8);
|
|
ZeroMem (TemStr, 2);
|
|
ZeroMem ((UINT8 *) Value, sizeof (Value));
|
|
SizeStr = AsciiStrLen (Str);
|
|
IndexValue = 0;
|
|
IndexNum = 0;
|
|
|
|
for (Index = 0; Index < SizeStr; Index ++) {
|
|
TemStr[0] = Str[Index];
|
|
TemValue = (UINT8) AsciiStrHexToUint64 (TemStr);
|
|
if (TemValue == 0 && TemStr[0] != '0') {
|
|
if ((TemStr[0] != '-') || (IndexNum == 0)) {
|
|
//
|
|
// Invalid Lun Char.
|
|
//
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
if ((TemValue == 0) && (TemStr[0] == '-')) {
|
|
//
|
|
// Next Lun value.
|
|
//
|
|
if (++IndexValue >= 4) {
|
|
//
|
|
// Max 4 Lun value.
|
|
//
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
//
|
|
// Restart str index for the next lun value.
|
|
//
|
|
IndexNum = 0;
|
|
continue;
|
|
}
|
|
|
|
if (++IndexNum > 4) {
|
|
//
|
|
// Each Lun Str can't exceed size 4, because it will be as UINT16 value.
|
|
//
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Combine UINT16 value.
|
|
//
|
|
Value[IndexValue] = (UINT16) ((Value[IndexValue] << 4) + TemValue);
|
|
}
|
|
|
|
for (Index = 0; Index <= IndexValue; Index ++) {
|
|
*((UINT16 *) &Lun[Index * 2]) = HTONS (Value[Index]);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Convert the 64-bit LUN into the hexadecimal encoded LUN string.
|
|
|
|
@param[in] Lun The 64-bit LUN.
|
|
@param[out] Str The storage to return the hexadecimal encoded LUN string.
|
|
|
|
**/
|
|
VOID
|
|
IScsiLunToUnicodeStr (
|
|
IN UINT8 *Lun,
|
|
OUT CHAR16 *Str
|
|
)
|
|
{
|
|
UINTN Index;
|
|
CHAR16 *TempStr;
|
|
|
|
TempStr = Str;
|
|
|
|
for (Index = 0; Index < 4; Index++) {
|
|
|
|
if ((Lun[2 * Index] | Lun[2 * Index + 1]) == 0) {
|
|
CopyMem (TempStr, L"0-", sizeof (L"0-"));
|
|
} else {
|
|
TempStr[0] = (CHAR16) IScsiHexString[Lun[2 * Index] >> 4];
|
|
TempStr[1] = (CHAR16) IScsiHexString[Lun[2 * Index] & 0x0F];
|
|
TempStr[2] = (CHAR16) IScsiHexString[Lun[2 * Index + 1] >> 4];
|
|
TempStr[3] = (CHAR16) IScsiHexString[Lun[2 * Index + 1] & 0x0F];
|
|
TempStr[4] = L'-';
|
|
TempStr[5] = 0;
|
|
|
|
IScsiStrTrim (TempStr, L'0');
|
|
}
|
|
|
|
TempStr += StrLen (TempStr);
|
|
}
|
|
//
|
|
// Remove the last '-'
|
|
//
|
|
ASSERT (StrLen(Str) >= 1);
|
|
Str[StrLen (Str) - 1] = 0;
|
|
|
|
for (Index = StrLen (Str) - 1; Index > 1; Index = Index - 2) {
|
|
if ((Str[Index] == L'0') && (Str[Index - 1] == L'-')) {
|
|
Str[Index - 1] = 0;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Convert the formatted IP address into the binary IP address.
|
|
|
|
@param[in] Str The UNICODE string.
|
|
@param[in] IpMode Indicates whether the IP address is v4 or v6.
|
|
@param[out] Ip The storage to return the ASCII string.
|
|
|
|
@retval EFI_SUCCESS The binary IP address is returned in Ip.
|
|
@retval EFI_INVALID_PARAMETER The IP string is malformatted or IpMode is
|
|
invalid.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
IScsiAsciiStrToIp (
|
|
IN CHAR8 *Str,
|
|
IN UINT8 IpMode,
|
|
OUT EFI_IP_ADDRESS *Ip
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
if (IpMode == IP_MODE_IP4 || IpMode == IP_MODE_AUTOCONFIG_IP4) {
|
|
return NetLibAsciiStrToIp4 (Str, &Ip->v4);
|
|
|
|
} else if (IpMode == IP_MODE_IP6 || IpMode == IP_MODE_AUTOCONFIG_IP6) {
|
|
return NetLibAsciiStrToIp6 (Str, &Ip->v6);
|
|
|
|
} else if (IpMode == IP_MODE_AUTOCONFIG) {
|
|
Status = NetLibAsciiStrToIp4 (Str, &Ip->v4);
|
|
if (!EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
return NetLibAsciiStrToIp6 (Str, &Ip->v6);
|
|
|
|
}
|
|
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
/**
|
|
Convert the mac address into a hexadecimal encoded "-" seperated string.
|
|
|
|
@param[in] Mac The mac address.
|
|
@param[in] Len Length in bytes of the mac address.
|
|
@param[in] VlanId VLAN ID of the network device.
|
|
@param[out] Str The storage to return the mac string.
|
|
|
|
**/
|
|
VOID
|
|
IScsiMacAddrToStr (
|
|
IN EFI_MAC_ADDRESS *Mac,
|
|
IN UINT32 Len,
|
|
IN UINT16 VlanId,
|
|
OUT CHAR16 *Str
|
|
)
|
|
{
|
|
UINT32 Index;
|
|
CHAR16 *String;
|
|
|
|
for (Index = 0; Index < Len; Index++) {
|
|
Str[3 * Index] = (CHAR16) IScsiHexString[(Mac->Addr[Index] >> 4) & 0x0F];
|
|
Str[3 * Index + 1] = (CHAR16) IScsiHexString[Mac->Addr[Index] & 0x0F];
|
|
Str[3 * Index + 2] = L':';
|
|
}
|
|
|
|
String = &Str[3 * Index - 1] ;
|
|
if (VlanId != 0) {
|
|
String += UnicodeSPrint (String, 6 * sizeof (CHAR16), L"\\%04x", (UINTN) VlanId);
|
|
}
|
|
|
|
*String = L'\0';
|
|
}
|
|
|
|
/**
|
|
Convert the binary encoded buffer into a hexadecimal encoded string.
|
|
|
|
@param[in] BinBuffer The buffer containing the binary data.
|
|
@param[in] BinLength Length of the binary buffer.
|
|
@param[in, out] HexStr Pointer to the string.
|
|
@param[in, out] HexLength The length of the string.
|
|
|
|
@retval EFI_SUCCESS The binary data is converted to the hexadecimal string
|
|
and the length of the string is updated.
|
|
@retval EFI_BUFFER_TOO_SMALL The string is too small.
|
|
@retval EFI_INVALID_PARAMETER The IP string is malformatted.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
IScsiBinToHex (
|
|
IN UINT8 *BinBuffer,
|
|
IN UINT32 BinLength,
|
|
IN OUT CHAR8 *HexStr,
|
|
IN OUT UINT32 *HexLength
|
|
)
|
|
{
|
|
UINTN Index;
|
|
|
|
if ((HexStr == NULL) || (BinBuffer == NULL) || (BinLength == 0)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (((*HexLength) - 3) < BinLength * 2) {
|
|
*HexLength = BinLength * 2 + 3;
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
*HexLength = BinLength * 2 + 3;
|
|
//
|
|
// Prefix for Hex String.
|
|
//
|
|
HexStr[0] = '0';
|
|
HexStr[1] = 'x';
|
|
|
|
for (Index = 0; Index < BinLength; Index++) {
|
|
HexStr[Index * 2 + 2] = IScsiHexString[BinBuffer[Index] >> 4];
|
|
HexStr[Index * 2 + 3] = IScsiHexString[BinBuffer[Index] & 0xf];
|
|
}
|
|
|
|
HexStr[Index * 2 + 2] = '\0';
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Convert the hexadecimal string into a binary encoded buffer.
|
|
|
|
@param[in, out] BinBuffer The binary buffer.
|
|
@param[in, out] BinLength Length of the binary buffer.
|
|
@param[in] HexStr The hexadecimal string.
|
|
|
|
@retval EFI_SUCCESS The hexadecimal string is converted into a binary
|
|
encoded buffer.
|
|
@retval EFI_BUFFER_TOO_SMALL The binary buffer is too small to hold the converted data.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
IScsiHexToBin (
|
|
IN OUT UINT8 *BinBuffer,
|
|
IN OUT UINT32 *BinLength,
|
|
IN CHAR8 *HexStr
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINTN Length;
|
|
UINT8 Digit;
|
|
CHAR8 TemStr[2];
|
|
|
|
ZeroMem (TemStr, sizeof (TemStr));
|
|
|
|
//
|
|
// Find out how many hex characters the string has.
|
|
//
|
|
if ((HexStr[0] == '0') && ((HexStr[1] == 'x') || (HexStr[1] == 'X'))) {
|
|
HexStr += 2;
|
|
}
|
|
|
|
Length = AsciiStrLen (HexStr);
|
|
|
|
for (Index = 0; Index < Length; Index ++) {
|
|
TemStr[0] = HexStr[Index];
|
|
Digit = (UINT8) AsciiStrHexToUint64 (TemStr);
|
|
if (Digit == 0 && TemStr[0] != '0') {
|
|
//
|
|
// Invalid Lun Char.
|
|
//
|
|
break;
|
|
}
|
|
if ((Index & 1) == 0) {
|
|
BinBuffer [Index/2] = Digit;
|
|
} else {
|
|
BinBuffer [Index/2] = (UINT8) ((BinBuffer [Index/2] << 4) + Digit);
|
|
}
|
|
}
|
|
|
|
*BinLength = (UINT32) ((Index + 1)/2);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Convert the decimal-constant string or hex-constant string into a numerical value.
|
|
|
|
@param[in] Str String in decimal or hex.
|
|
|
|
@return The numerical value.
|
|
|
|
**/
|
|
UINTN
|
|
IScsiNetNtoi (
|
|
IN CHAR8 *Str
|
|
)
|
|
{
|
|
if ((Str[0] == '0') && ((Str[1] == 'x') || (Str[1] == 'X'))) {
|
|
Str += 2;
|
|
|
|
return AsciiStrHexToUintn (Str);
|
|
}
|
|
|
|
return AsciiStrDecimalToUintn (Str);
|
|
}
|
|
|
|
|
|
/**
|
|
Generate random numbers.
|
|
|
|
@param[in, out] Rand The buffer to contain random numbers.
|
|
@param[in] RandLength The length of the Rand buffer.
|
|
|
|
**/
|
|
VOID
|
|
IScsiGenRandom (
|
|
IN OUT UINT8 *Rand,
|
|
IN UINTN RandLength
|
|
)
|
|
{
|
|
UINT32 Random;
|
|
|
|
while (RandLength > 0) {
|
|
Random = NET_RANDOM (NetRandomInitSeed ());
|
|
*Rand++ = (UINT8) (Random);
|
|
RandLength--;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
Record the NIC info in global structure.
|
|
|
|
@param[in] Controller The handle of the controller.
|
|
|
|
@retval EFI_SUCCESS The operation is completed.
|
|
@retval EFI_OUT_OF_RESOURCES Do not have sufficient resources to finish this
|
|
operation.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
IScsiAddNic (
|
|
IN EFI_HANDLE Controller
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
ISCSI_NIC_INFO *NicInfo;
|
|
LIST_ENTRY *Entry;
|
|
EFI_MAC_ADDRESS MacAddr;
|
|
UINTN HwAddressSize;
|
|
UINT16 VlanId;
|
|
|
|
//
|
|
// Get MAC address of this network device.
|
|
//
|
|
Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Get VLAN ID of this network device.
|
|
//
|
|
VlanId = NetLibGetVlanId (Controller);
|
|
|
|
//
|
|
// Check whether the NIC info already exists. Return directly if so.
|
|
//
|
|
NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
|
|
NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
|
|
if (NicInfo->HwAddressSize == HwAddressSize &&
|
|
CompareMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize) == 0 &&
|
|
NicInfo->VlanId == VlanId) {
|
|
mPrivate->CurrentNic = NicInfo->NicIndex;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (mPrivate->MaxNic < NicInfo->NicIndex) {
|
|
mPrivate->MaxNic = NicInfo->NicIndex;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Record the NIC info in private structure.
|
|
//
|
|
NicInfo = AllocateZeroPool (sizeof (ISCSI_NIC_INFO));
|
|
if (NicInfo == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
CopyMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize);
|
|
NicInfo->HwAddressSize = (UINT32) HwAddressSize;
|
|
NicInfo->VlanId = VlanId;
|
|
NicInfo->NicIndex = (UINT8) (mPrivate->MaxNic + 1);
|
|
mPrivate->MaxNic = NicInfo->NicIndex;
|
|
|
|
//
|
|
// Get the PCI location.
|
|
//
|
|
IScsiGetNICPciLocation (
|
|
Controller,
|
|
&NicInfo->BusNumber,
|
|
&NicInfo->DeviceNumber,
|
|
&NicInfo->FunctionNumber
|
|
);
|
|
|
|
InsertTailList (&mPrivate->NicInfoList, &NicInfo->Link);
|
|
mPrivate->NicCount++;
|
|
|
|
mPrivate->CurrentNic = NicInfo->NicIndex;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Delete the recorded NIC info from global structure. Also delete corresponding
|
|
attempts.
|
|
|
|
@param[in] Controller The handle of the controller.
|
|
|
|
@retval EFI_SUCCESS The operation is completed.
|
|
@retval EFI_NOT_FOUND The NIC info to be deleted is not recorded.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
IScsiRemoveNic (
|
|
IN EFI_HANDLE Controller
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
ISCSI_NIC_INFO *NicInfo;
|
|
LIST_ENTRY *Entry;
|
|
LIST_ENTRY *NextEntry;
|
|
ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
|
|
ISCSI_NIC_INFO *ThisNic;
|
|
EFI_MAC_ADDRESS MacAddr;
|
|
UINTN HwAddressSize;
|
|
UINT16 VlanId;
|
|
|
|
//
|
|
// Get MAC address of this network device.
|
|
//
|
|
Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Get VLAN ID of this network device.
|
|
//
|
|
VlanId = NetLibGetVlanId (Controller);
|
|
|
|
//
|
|
// Check whether the NIC information exists.
|
|
//
|
|
ThisNic = NULL;
|
|
|
|
NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
|
|
NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
|
|
if (NicInfo->HwAddressSize == HwAddressSize &&
|
|
CompareMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize) == 0 &&
|
|
NicInfo->VlanId == VlanId) {
|
|
|
|
ThisNic = NicInfo;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ThisNic == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
mPrivate->CurrentNic = ThisNic->NicIndex;
|
|
|
|
RemoveEntryList (&ThisNic->Link);
|
|
FreePool (ThisNic);
|
|
mPrivate->NicCount--;
|
|
|
|
//
|
|
// Remove all attempts related to this NIC.
|
|
//
|
|
NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mPrivate->AttemptConfigs) {
|
|
AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
|
|
if (AttemptConfigData->NicIndex == mPrivate->CurrentNic) {
|
|
RemoveEntryList (&AttemptConfigData->Link);
|
|
mPrivate->AttemptCount--;
|
|
|
|
if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO && mPrivate->MpioCount > 0) {
|
|
if (--mPrivate->MpioCount == 0) {
|
|
mPrivate->EnableMpio = FALSE;
|
|
}
|
|
|
|
if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB && mPrivate->Krb5MpioCount > 0) {
|
|
mPrivate->Krb5MpioCount--;
|
|
}
|
|
|
|
} else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED && mPrivate->SinglePathCount > 0) {
|
|
mPrivate->SinglePathCount--;
|
|
|
|
if (mPrivate->ValidSinglePathCount > 0) {
|
|
mPrivate->ValidSinglePathCount--;
|
|
}
|
|
}
|
|
|
|
FreePool (AttemptConfigData);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free attempt is created but not saved to system.
|
|
//
|
|
if (mPrivate->NewAttempt != NULL) {
|
|
FreePool (mPrivate->NewAttempt);
|
|
mPrivate->NewAttempt = NULL;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Get the recorded NIC info from global structure by the Index.
|
|
|
|
@param[in] NicIndex The index indicates the position of NIC info.
|
|
|
|
@return Pointer to the NIC info, or NULL if not found.
|
|
|
|
**/
|
|
ISCSI_NIC_INFO *
|
|
IScsiGetNicInfoByIndex (
|
|
IN UINT8 NicIndex
|
|
)
|
|
{
|
|
LIST_ENTRY *Entry;
|
|
ISCSI_NIC_INFO *NicInfo;
|
|
|
|
NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
|
|
NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
|
|
if (NicInfo->NicIndex == NicIndex) {
|
|
return NicInfo;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/**
|
|
Get the NIC's PCI location and return it according to the composited
|
|
format defined in iSCSI Boot Firmware Table.
|
|
|
|
@param[in] Controller The handle of the controller.
|
|
@param[out] Bus The bus number.
|
|
@param[out] Device The device number.
|
|
@param[out] Function The function number.
|
|
|
|
@return The composited representation of the NIC PCI location.
|
|
|
|
**/
|
|
UINT16
|
|
IScsiGetNICPciLocation (
|
|
IN EFI_HANDLE Controller,
|
|
OUT UINTN *Bus,
|
|
OUT UINTN *Device,
|
|
OUT UINTN *Function
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
EFI_HANDLE PciIoHandle;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
UINTN Segment;
|
|
|
|
Status = gBS->HandleProtocol (
|
|
Controller,
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID **) &DevicePath
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return 0;
|
|
}
|
|
|
|
Status = gBS->LocateDevicePath (
|
|
&gEfiPciIoProtocolGuid,
|
|
&DevicePath,
|
|
&PciIoHandle
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return 0;
|
|
}
|
|
|
|
Status = gBS->HandleProtocol (PciIoHandle, &gEfiPciIoProtocolGuid, (VOID **) &PciIo);
|
|
if (EFI_ERROR (Status)) {
|
|
return 0;
|
|
}
|
|
|
|
Status = PciIo->GetLocation (PciIo, &Segment, Bus, Device, Function);
|
|
if (EFI_ERROR (Status)) {
|
|
return 0;
|
|
}
|
|
|
|
return (UINT16) ((*Bus << 8) | (*Device << 3) | *Function);
|
|
}
|
|
|
|
|
|
/**
|
|
Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
|
|
buffer, and the size of the buffer. If failure, return NULL.
|
|
|
|
@param[in] Name String part of EFI variable name.
|
|
@param[in] VendorGuid GUID part of EFI variable name.
|
|
@param[out] VariableSize Returns the size of the EFI variable that was read.
|
|
|
|
@return Dynamically allocated memory that contains a copy of the EFI variable.
|
|
@return Caller is responsible freeing the buffer.
|
|
@retval NULL Variable was not read.
|
|
|
|
**/
|
|
VOID *
|
|
IScsiGetVariableAndSize (
|
|
IN CHAR16 *Name,
|
|
IN EFI_GUID *VendorGuid,
|
|
OUT UINTN *VariableSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN BufferSize;
|
|
VOID *Buffer;
|
|
|
|
Buffer = NULL;
|
|
|
|
//
|
|
// Pass in a zero size buffer to find the required buffer size.
|
|
//
|
|
BufferSize = 0;
|
|
Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
//
|
|
// Allocate the buffer to return
|
|
//
|
|
Buffer = AllocateZeroPool (BufferSize);
|
|
if (Buffer == NULL) {
|
|
return NULL;
|
|
}
|
|
//
|
|
// Read variable into the allocated buffer.
|
|
//
|
|
Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
|
|
if (EFI_ERROR (Status)) {
|
|
BufferSize = 0;
|
|
}
|
|
}
|
|
|
|
*VariableSize = BufferSize;
|
|
return Buffer;
|
|
}
|
|
|
|
|
|
/**
|
|
Create the iSCSI driver data.
|
|
|
|
@param[in] Image The handle of the driver image.
|
|
@param[in] Controller The handle of the controller.
|
|
|
|
@return The iSCSI driver data created.
|
|
@retval NULL Other errors as indicated.
|
|
|
|
**/
|
|
ISCSI_DRIVER_DATA *
|
|
IScsiCreateDriverData (
|
|
IN EFI_HANDLE Image,
|
|
IN EFI_HANDLE Controller
|
|
)
|
|
{
|
|
ISCSI_DRIVER_DATA *Private;
|
|
EFI_STATUS Status;
|
|
|
|
Private = AllocateZeroPool (sizeof (ISCSI_DRIVER_DATA));
|
|
if (Private == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
Private->Signature = ISCSI_DRIVER_DATA_SIGNATURE;
|
|
Private->Image = Image;
|
|
Private->Controller = Controller;
|
|
Private->Session = NULL;
|
|
|
|
//
|
|
// Create an event to be signaled when the BS to RT transition is triggerd so
|
|
// as to abort the iSCSI session.
|
|
//
|
|
Status = gBS->CreateEventEx (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
IScsiOnExitBootService,
|
|
Private,
|
|
&gEfiEventExitBootServicesGuid,
|
|
&Private->ExitBootServiceEvent
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
FreePool (Private);
|
|
return NULL;
|
|
}
|
|
|
|
Private->ExtScsiPassThruHandle = NULL;
|
|
CopyMem(&Private->IScsiExtScsiPassThru, &gIScsiExtScsiPassThruProtocolTemplate, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL));
|
|
|
|
//
|
|
// 0 is designated to the TargetId, so use another value for the AdapterId.
|
|
//
|
|
Private->ExtScsiPassThruMode.AdapterId = 2;
|
|
Private->ExtScsiPassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
|
|
Private->ExtScsiPassThruMode.IoAlign = 4;
|
|
Private->IScsiExtScsiPassThru.Mode = &Private->ExtScsiPassThruMode;
|
|
|
|
return Private;
|
|
}
|
|
|
|
|
|
/**
|
|
Clean the iSCSI driver data.
|
|
|
|
@param[in] Private The iSCSI driver data.
|
|
|
|
**/
|
|
VOID
|
|
IScsiCleanDriverData (
|
|
IN ISCSI_DRIVER_DATA *Private
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
if (Private->DevicePath != NULL) {
|
|
gBS->UninstallProtocolInterface (
|
|
Private->ExtScsiPassThruHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
Private->DevicePath
|
|
);
|
|
|
|
FreePool (Private->DevicePath);
|
|
}
|
|
|
|
if (Private->ExtScsiPassThruHandle != NULL) {
|
|
Status = gBS->UninstallProtocolInterface (
|
|
Private->ExtScsiPassThruHandle,
|
|
&gEfiExtScsiPassThruProtocolGuid,
|
|
&Private->IScsiExtScsiPassThru
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
mPrivate->OneSessionEstablished = FALSE;
|
|
}
|
|
}
|
|
|
|
gBS->CloseEvent (Private->ExitBootServiceEvent);
|
|
|
|
FreePool (Private);
|
|
}
|
|
|
|
/**
|
|
Check wheather the Controller handle is configured to use DHCP protocol.
|
|
|
|
@param[in] Controller The handle of the controller.
|
|
@param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
|
|
|
|
@retval TRUE The handle of the controller need the Dhcp protocol.
|
|
@retval FALSE The handle of the controller does not need the Dhcp protocol.
|
|
|
|
**/
|
|
BOOLEAN
|
|
IScsiDhcpIsConfigured (
|
|
IN EFI_HANDLE Controller,
|
|
IN UINT8 IpVersion
|
|
)
|
|
{
|
|
ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptTmp;
|
|
UINT8 *AttemptConfigOrder;
|
|
UINTN AttemptConfigOrderSize;
|
|
UINTN Index;
|
|
EFI_STATUS Status;
|
|
EFI_MAC_ADDRESS MacAddr;
|
|
UINTN HwAddressSize;
|
|
UINT16 VlanId;
|
|
CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN];
|
|
CHAR16 AttemptName[ISCSI_NAME_IFR_MAX_SIZE];
|
|
|
|
AttemptConfigOrder = IScsiGetVariableAndSize (
|
|
L"AttemptOrder",
|
|
&gIScsiConfigGuid,
|
|
&AttemptConfigOrderSize
|
|
);
|
|
if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Get MAC address of this network device.
|
|
//
|
|
Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);
|
|
if(EFI_ERROR (Status)) {
|
|
return FALSE;
|
|
}
|
|
//
|
|
// Get VLAN ID of this network device.
|
|
//
|
|
VlanId = NetLibGetVlanId (Controller);
|
|
IScsiMacAddrToStr (&MacAddr, (UINT32) HwAddressSize, VlanId, MacString);
|
|
|
|
for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
|
|
UnicodeSPrint (
|
|
AttemptName,
|
|
(UINTN) 128,
|
|
L"%s%d",
|
|
MacString,
|
|
(UINTN) AttemptConfigOrder[Index]
|
|
);
|
|
Status = GetVariable2 (
|
|
AttemptName,
|
|
&gEfiIScsiInitiatorNameProtocolGuid,
|
|
(VOID**)&AttemptTmp,
|
|
NULL
|
|
);
|
|
if(AttemptTmp == NULL || EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
ASSERT (AttemptConfigOrder[Index] == AttemptTmp->AttemptConfigIndex);
|
|
|
|
if (AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED) {
|
|
FreePool (AttemptTmp);
|
|
continue;
|
|
}
|
|
|
|
if (AttemptTmp->SessionConfigData.IpMode != IP_MODE_AUTOCONFIG &&
|
|
AttemptTmp->SessionConfigData.IpMode != ((IpVersion == IP_VERSION_4) ? IP_MODE_IP4 : IP_MODE_IP6)) {
|
|
FreePool (AttemptTmp);
|
|
continue;
|
|
}
|
|
|
|
if(AttemptTmp->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG ||
|
|
AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp == TRUE ||
|
|
AttemptTmp->SessionConfigData.TargetInfoFromDhcp == TRUE) {
|
|
FreePool (AttemptTmp);
|
|
FreePool (AttemptConfigOrder);
|
|
return TRUE;
|
|
}
|
|
|
|
FreePool (AttemptTmp);
|
|
}
|
|
|
|
FreePool (AttemptConfigOrder);
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Get the various configuration data.
|
|
|
|
@param[in] Private The iSCSI driver data.
|
|
|
|
@retval EFI_SUCCESS The configuration data is retrieved.
|
|
@retval EFI_NOT_FOUND This iSCSI driver is not configured yet.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
IScsiGetConfigData (
|
|
IN ISCSI_DRIVER_DATA *Private
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN];
|
|
UINTN Index;
|
|
ISCSI_NIC_INFO *NicInfo;
|
|
ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
|
|
ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptTmp;
|
|
UINT8 *AttemptConfigOrder;
|
|
UINTN AttemptConfigOrderSize;
|
|
CHAR16 IScsiMode[64];
|
|
CHAR16 IpMode[64];
|
|
|
|
//
|
|
// There should be at least one attempt configured.
|
|
//
|
|
AttemptConfigOrder = IScsiGetVariableAndSize (
|
|
L"AttemptOrder",
|
|
&gIScsiConfigGuid,
|
|
&AttemptConfigOrderSize
|
|
);
|
|
if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Get the iSCSI Initiator Name.
|
|
//
|
|
mPrivate->InitiatorNameLength = ISCSI_NAME_MAX_SIZE;
|
|
Status = gIScsiInitiatorName.Get (
|
|
&gIScsiInitiatorName,
|
|
&mPrivate->InitiatorNameLength,
|
|
mPrivate->InitiatorName
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Get the normal configuration.
|
|
//
|
|
for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
|
|
|
|
//
|
|
// Check whether the attempt exists in AttemptConfig.
|
|
//
|
|
AttemptTmp = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]);
|
|
if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED) {
|
|
continue;
|
|
} else if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled != ISCSI_DISABLED) {
|
|
//
|
|
// Check the autoconfig path to see whether it should be retried.
|
|
//
|
|
if (AttemptTmp->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&
|
|
!AttemptTmp->AutoConfigureSuccess) {
|
|
if (mPrivate->Ipv6Flag &&
|
|
AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6) {
|
|
//
|
|
// Autoconfigure for IP6 already attempted but failed. Do not try again.
|
|
//
|
|
continue;
|
|
} else if (!mPrivate->Ipv6Flag &&
|
|
AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4) {
|
|
//
|
|
// Autoconfigure for IP4 already attempted but failed. Do not try again.
|
|
//
|
|
continue;
|
|
} else {
|
|
//
|
|
// Try another approach for this autoconfigure path.
|
|
//
|
|
AttemptTmp->AutoConfigureMode =
|
|
(UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);
|
|
AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp = TRUE;
|
|
AttemptTmp->SessionConfigData.TargetInfoFromDhcp = TRUE;
|
|
AttemptTmp->DhcpSuccess = FALSE;
|
|
|
|
//
|
|
// Get some information from the dhcp server.
|
|
//
|
|
if (!mPrivate->Ipv6Flag) {
|
|
Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);
|
|
if (!EFI_ERROR (Status)) {
|
|
AttemptTmp->DhcpSuccess = TRUE;
|
|
}
|
|
} else {
|
|
Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);
|
|
if (!EFI_ERROR (Status)) {
|
|
AttemptTmp->DhcpSuccess = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Refresh the state of this attempt to NVR.
|
|
//
|
|
AsciiStrToUnicodeStr (AttemptTmp->MacString, MacString);
|
|
UnicodeSPrint (
|
|
mPrivate->PortString,
|
|
(UINTN) ISCSI_NAME_IFR_MAX_SIZE,
|
|
L"%s%d",
|
|
MacString,
|
|
(UINTN) AttemptTmp->AttemptConfigIndex
|
|
);
|
|
|
|
gRT->SetVariable (
|
|
mPrivate->PortString,
|
|
&gEfiIScsiInitiatorNameProtocolGuid,
|
|
ISCSI_CONFIG_VAR_ATTR,
|
|
sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
|
|
AttemptTmp
|
|
);
|
|
|
|
continue;
|
|
}
|
|
} else if (AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp && !AttemptTmp->ValidPath) {
|
|
//
|
|
// Get DHCP information for already added, but failed, attempt.
|
|
//
|
|
AttemptTmp->DhcpSuccess = FALSE;
|
|
if (!mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP4)) {
|
|
Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);
|
|
if (!EFI_ERROR (Status)) {
|
|
AttemptTmp->DhcpSuccess = TRUE;
|
|
}
|
|
} else if (mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP6)) {
|
|
Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);
|
|
if (!EFI_ERROR (Status)) {
|
|
AttemptTmp->DhcpSuccess = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Refresh the state of this attempt to NVR.
|
|
//
|
|
AsciiStrToUnicodeStr (AttemptTmp->MacString, MacString);
|
|
UnicodeSPrint (
|
|
mPrivate->PortString,
|
|
(UINTN) ISCSI_NAME_IFR_MAX_SIZE,
|
|
L"%s%d",
|
|
MacString,
|
|
(UINTN) AttemptTmp->AttemptConfigIndex
|
|
);
|
|
|
|
gRT->SetVariable (
|
|
mPrivate->PortString,
|
|
&gEfiIScsiInitiatorNameProtocolGuid,
|
|
ISCSI_CONFIG_VAR_ATTR,
|
|
sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
|
|
AttemptTmp
|
|
);
|
|
|
|
continue;
|
|
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// This attempt does not exist in AttemptConfig. Try to add a new one.
|
|
//
|
|
|
|
NicInfo = IScsiGetNicInfoByIndex (mPrivate->CurrentNic);
|
|
ASSERT (NicInfo != NULL);
|
|
IScsiMacAddrToStr (&NicInfo->PermanentAddress, NicInfo->HwAddressSize, NicInfo->VlanId, MacString);
|
|
UnicodeSPrint (
|
|
mPrivate->PortString,
|
|
(UINTN) 128,
|
|
L"%s%d",
|
|
MacString,
|
|
(UINTN) AttemptConfigOrder[Index]
|
|
);
|
|
|
|
GetVariable2 (
|
|
mPrivate->PortString,
|
|
&gEfiIScsiInitiatorNameProtocolGuid,
|
|
(VOID**)&AttemptConfigData,
|
|
NULL
|
|
);
|
|
|
|
if (AttemptConfigData == NULL) {
|
|
continue;
|
|
}
|
|
|
|
ASSERT (AttemptConfigOrder[Index] == AttemptConfigData->AttemptConfigIndex);
|
|
|
|
AttemptConfigData->NicIndex = NicInfo->NicIndex;
|
|
AttemptConfigData->DhcpSuccess = FALSE;
|
|
AttemptConfigData->ValidiBFTPath = (BOOLEAN) (mPrivate->EnableMpio ? TRUE : FALSE);
|
|
AttemptConfigData->ValidPath = FALSE;
|
|
|
|
if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {
|
|
AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp = TRUE;
|
|
AttemptConfigData->SessionConfigData.TargetInfoFromDhcp = TRUE;
|
|
|
|
AttemptConfigData->AutoConfigureMode =
|
|
(UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);
|
|
AttemptConfigData->AutoConfigureSuccess = FALSE;
|
|
}
|
|
|
|
//
|
|
// Get some information from dhcp server.
|
|
//
|
|
if (AttemptConfigData->SessionConfigData.Enabled != ISCSI_DISABLED &&
|
|
AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp) {
|
|
|
|
if (!mPrivate->Ipv6Flag &&
|
|
(AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4 ||
|
|
AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4)) {
|
|
Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptConfigData);
|
|
if (!EFI_ERROR (Status)) {
|
|
AttemptConfigData->DhcpSuccess = TRUE;
|
|
}
|
|
} else if (mPrivate->Ipv6Flag &&
|
|
(AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6 ||
|
|
AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6)) {
|
|
Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptConfigData);
|
|
if (!EFI_ERROR (Status)) {
|
|
AttemptConfigData->DhcpSuccess = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Refresh the state of this attempt to NVR.
|
|
//
|
|
AsciiStrToUnicodeStr (AttemptConfigData->MacString, MacString);
|
|
UnicodeSPrint (
|
|
mPrivate->PortString,
|
|
(UINTN) ISCSI_NAME_IFR_MAX_SIZE,
|
|
L"%s%d",
|
|
MacString,
|
|
(UINTN) AttemptConfigData->AttemptConfigIndex
|
|
);
|
|
|
|
gRT->SetVariable (
|
|
mPrivate->PortString,
|
|
&gEfiIScsiInitiatorNameProtocolGuid,
|
|
ISCSI_CONFIG_VAR_ATTR,
|
|
sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
|
|
AttemptConfigData
|
|
);
|
|
}
|
|
|
|
//
|
|
// Update Attempt Help Info.
|
|
//
|
|
|
|
if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_DISABLED) {
|
|
UnicodeSPrint (IScsiMode, 64, L"Disabled");
|
|
} else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {
|
|
UnicodeSPrint (IScsiMode, 64, L"Enabled");
|
|
} else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
|
|
UnicodeSPrint (IScsiMode, 64, L"Enabled for MPIO");
|
|
}
|
|
|
|
if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4) {
|
|
UnicodeSPrint (IpMode, 64, L"IP4");
|
|
} else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6) {
|
|
UnicodeSPrint (IpMode, 64, L"IP6");
|
|
} else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {
|
|
UnicodeSPrint (IpMode, 64, L"Autoconfigure");
|
|
}
|
|
|
|
UnicodeSPrint (
|
|
mPrivate->PortString,
|
|
(UINTN) ISCSI_NAME_IFR_MAX_SIZE,
|
|
L"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s",
|
|
MacString,
|
|
NicInfo->BusNumber,
|
|
NicInfo->DeviceNumber,
|
|
NicInfo->FunctionNumber,
|
|
IScsiMode,
|
|
IpMode
|
|
);
|
|
|
|
AttemptConfigData->AttemptTitleHelpToken = HiiSetString (
|
|
mCallbackInfo->RegisteredHandle,
|
|
0,
|
|
mPrivate->PortString,
|
|
NULL
|
|
);
|
|
ASSERT (AttemptConfigData->AttemptTitleHelpToken != 0);
|
|
|
|
//
|
|
// Record the attempt in global link list.
|
|
//
|
|
InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);
|
|
mPrivate->AttemptCount++;
|
|
|
|
if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
|
|
mPrivate->MpioCount++;
|
|
mPrivate->EnableMpio = TRUE;
|
|
|
|
if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB) {
|
|
mPrivate->Krb5MpioCount++;
|
|
}
|
|
} else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {
|
|
mPrivate->SinglePathCount++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Reorder the AttemptConfig by the configured order.
|
|
//
|
|
for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
|
|
AttemptConfigData = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]);
|
|
if (AttemptConfigData == NULL) {
|
|
continue;
|
|
}
|
|
|
|
RemoveEntryList (&AttemptConfigData->Link);
|
|
InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);
|
|
}
|
|
|
|
//
|
|
// Update the Main Form.
|
|
//
|
|
IScsiConfigUpdateAttempt ();
|
|
|
|
FreePool (AttemptConfigOrder);
|
|
|
|
//
|
|
// There should be at least one attempt configuration.
|
|
//
|
|
if (!mPrivate->EnableMpio) {
|
|
if (mPrivate->SinglePathCount == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
mPrivate->ValidSinglePathCount = mPrivate->SinglePathCount;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Get the device path of the iSCSI tcp connection and update it.
|
|
|
|
@param Session The iSCSI session.
|
|
|
|
@return The updated device path.
|
|
@retval NULL Other errors as indicated.
|
|
|
|
**/
|
|
EFI_DEVICE_PATH_PROTOCOL *
|
|
IScsiGetTcpConnDevicePath (
|
|
IN ISCSI_SESSION *Session
|
|
)
|
|
{
|
|
ISCSI_CONNECTION *Conn;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
EFI_STATUS Status;
|
|
EFI_DEV_PATH *DPathNode;
|
|
UINTN PathLen;
|
|
|
|
if (Session->State != SESSION_STATE_LOGGED_IN) {
|
|
return NULL;
|
|
}
|
|
|
|
Conn = NET_LIST_USER_STRUCT_S (
|
|
Session->Conns.ForwardLink,
|
|
ISCSI_CONNECTION,
|
|
Link,
|
|
ISCSI_CONNECTION_SIGNATURE
|
|
);
|
|
|
|
Status = gBS->HandleProtocol (
|
|
Conn->TcpIo.Handle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID **) &DevicePath
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return NULL;
|
|
}
|
|
//
|
|
// Duplicate it.
|
|
//
|
|
DevicePath = DuplicateDevicePath (DevicePath);
|
|
if (DevicePath == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
DPathNode = (EFI_DEV_PATH *) DevicePath;
|
|
|
|
while (!IsDevicePathEnd (&DPathNode->DevPath)) {
|
|
if (DevicePathType (&DPathNode->DevPath) == MESSAGING_DEVICE_PATH) {
|
|
if (!Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv4_DP) {
|
|
DPathNode->Ipv4.LocalPort = 0;
|
|
|
|
DPathNode->Ipv4.StaticIpAddress =
|
|
(BOOLEAN) (!Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp);
|
|
|
|
//
|
|
// Add a judgement here to support previous versions of IPv4_DEVICE_PATH.
|
|
// In previous versions of IPv4_DEVICE_PATH, GatewayIpAddress and SubnetMask
|
|
// do not exist.
|
|
// In new version of IPv4_DEVICE_PATH, structcure length is 27.
|
|
//
|
|
|
|
PathLen = DevicePathNodeLength (&DPathNode->Ipv4);
|
|
|
|
if (PathLen == IP4_NODE_LEN_NEW_VERSIONS) {
|
|
|
|
IP4_COPY_ADDRESS (
|
|
&DPathNode->Ipv4.GatewayIpAddress,
|
|
&Session->ConfigData->SessionConfigData.Gateway
|
|
);
|
|
|
|
IP4_COPY_ADDRESS (
|
|
&DPathNode->Ipv4.SubnetMask,
|
|
&Session->ConfigData->SessionConfigData.SubnetMask
|
|
);
|
|
}
|
|
|
|
break;
|
|
} else if (Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv6_DP) {
|
|
DPathNode->Ipv6.LocalPort = 0;
|
|
|
|
//
|
|
// Add a judgement here to support previous versions of IPv6_DEVICE_PATH.
|
|
// In previous versions of IPv6_DEVICE_PATH, IpAddressOrigin, PrefixLength
|
|
// and GatewayIpAddress do not exist.
|
|
// In new version of IPv6_DEVICE_PATH, structure length is 60, while in
|
|
// old versions, the length is 43.
|
|
//
|
|
|
|
PathLen = DevicePathNodeLength (&DPathNode->Ipv6);
|
|
|
|
if (PathLen == IP6_NODE_LEN_NEW_VERSIONS ) {
|
|
|
|
DPathNode->Ipv6.IpAddressOrigin = 0;
|
|
DPathNode->Ipv6.PrefixLength = IP6_PREFIX_LENGTH;
|
|
ZeroMem (&DPathNode->Ipv6.GatewayIpAddress, sizeof (EFI_IPv6_ADDRESS));
|
|
}
|
|
else if (PathLen == IP6_NODE_LEN_OLD_VERSIONS) {
|
|
|
|
//
|
|
// StaticIPAddress is a field in old versions of IPv6_DEVICE_PATH, while ignored in new
|
|
// version. Set StaticIPAddress through its' offset in old IPv6_DEVICE_PATH.
|
|
//
|
|
*((UINT8 *)(&DPathNode->Ipv6) + IP6_OLD_IPADDRESS_OFFSET) =
|
|
(BOOLEAN) (!Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
DPathNode = (EFI_DEV_PATH *) NextDevicePathNode (&DPathNode->DevPath);
|
|
}
|
|
|
|
return DevicePath;
|
|
}
|
|
|
|
|
|
/**
|
|
Abort the session when the transition from BS to RT is initiated.
|
|
|
|
@param[in] Event The event signaled.
|
|
@param[in] Context The iSCSI driver data.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
IScsiOnExitBootService (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
ISCSI_DRIVER_DATA *Private;
|
|
|
|
Private = (ISCSI_DRIVER_DATA *) Context;
|
|
gBS->CloseEvent (Private->ExitBootServiceEvent);
|
|
|
|
if (Private->Session != NULL) {
|
|
IScsiSessionAbort (Private->Session);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Tests whether a controller handle is being managed by IScsi driver.
|
|
|
|
This function tests whether the driver specified by DriverBindingHandle is
|
|
currently managing the controller specified by ControllerHandle. This test
|
|
is performed by evaluating if the the protocol specified by ProtocolGuid is
|
|
present on ControllerHandle and is was opened by DriverBindingHandle and Nic
|
|
Device handle with an attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
|
|
If ProtocolGuid is NULL, then ASSERT().
|
|
|
|
@param ControllerHandle A handle for a controller to test.
|
|
@param DriverBindingHandle Specifies the driver binding handle for the
|
|
driver.
|
|
@param ProtocolGuid Specifies the protocol that the driver specified
|
|
by DriverBindingHandle opens in its Start()
|
|
function.
|
|
|
|
@retval EFI_SUCCESS ControllerHandle is managed by the driver
|
|
specified by DriverBindingHandle.
|
|
@retval EFI_UNSUPPORTED ControllerHandle is not managed by the driver
|
|
specified by DriverBindingHandle.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
IScsiTestManagedDevice (
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_HANDLE DriverBindingHandle,
|
|
IN EFI_GUID *ProtocolGuid
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VOID *ManagedInterface;
|
|
EFI_HANDLE NicControllerHandle;
|
|
|
|
ASSERT (ProtocolGuid != NULL);
|
|
|
|
NicControllerHandle = NetLibGetNicHandle (ControllerHandle, ProtocolGuid);
|
|
if (NicControllerHandle == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Status = gBS->OpenProtocol (
|
|
ControllerHandle,
|
|
(EFI_GUID *) ProtocolGuid,
|
|
&ManagedInterface,
|
|
DriverBindingHandle,
|
|
NicControllerHandle,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
gBS->CloseProtocol (
|
|
ControllerHandle,
|
|
(EFI_GUID *) ProtocolGuid,
|
|
DriverBindingHandle,
|
|
NicControllerHandle
|
|
);
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (Status != EFI_ALREADY_STARTED) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|