]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/IScsiDxe/IScsiMisc.c
NetworkPkg: Clean up source files
[mirror_edk2.git] / NetworkPkg / IScsiDxe / IScsiMisc.c
1 /** @file
2 Miscellaneous routines for iSCSI driver.
3
4 Copyright (c) 2004 - 2018, 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
9
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.
12
13 **/
14
15 #include "IScsiImpl.h"
16
17 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 IScsiHexString[] = "0123456789ABCDEFabcdef";
18
19 /**
20 Removes (trims) specified leading and trailing characters from a string.
21
22 @param[in, out] Str Pointer to the null-terminated string to be trimmed.
23 On return, Str will hold the trimmed string.
24
25 @param[in] CharC Character will be trimmed from str.
26
27 **/
28 VOID
29 IScsiStrTrim (
30 IN OUT CHAR16 *Str,
31 IN CHAR16 CharC
32 )
33 {
34 CHAR16 *Pointer1;
35 CHAR16 *Pointer2;
36
37 if (*Str == 0) {
38 return ;
39 }
40
41 //
42 // Trim off the leading and trailing characters c
43 //
44 for (Pointer1 = Str; (*Pointer1 != 0) && (*Pointer1 == CharC); Pointer1++) {
45 ;
46 }
47
48 Pointer2 = Str;
49 if (Pointer2 == Pointer1) {
50 while (*Pointer1 != 0) {
51 Pointer2++;
52 Pointer1++;
53 }
54 } else {
55 while (*Pointer1 != 0) {
56 *Pointer2 = *Pointer1;
57 Pointer1++;
58 Pointer2++;
59 }
60 *Pointer2 = 0;
61 }
62
63
64 for (Pointer1 = Str + StrLen(Str) - 1; Pointer1 >= Str && *Pointer1 == CharC; Pointer1--) {
65 ;
66 }
67 if (Pointer1 != Str + StrLen(Str) - 1) {
68 *(Pointer1 + 1) = 0;
69 }
70 }
71
72 /**
73 Calculate the prefix length of the IPv4 subnet mask.
74
75 @param[in] SubnetMask The IPv4 subnet mask.
76
77 @return The prefix length of the subnet mask.
78 @retval 0 Other errors as indicated.
79
80 **/
81 UINT8
82 IScsiGetSubnetMaskPrefixLength (
83 IN EFI_IPv4_ADDRESS *SubnetMask
84 )
85 {
86 UINT8 Len;
87 UINT32 ReverseMask;
88
89 //
90 // The SubnetMask is in network byte order.
91 //
92 ReverseMask = (SubnetMask->Addr[0] << 24) | (SubnetMask->Addr[1] << 16) | (SubnetMask->Addr[2] << 8) | (SubnetMask->Addr[3]);
93
94 //
95 // Reverse it.
96 //
97 ReverseMask = ~ReverseMask;
98
99 if ((ReverseMask & (ReverseMask + 1)) != 0) {
100 return 0;
101 }
102
103 Len = 0;
104
105 while (ReverseMask != 0) {
106 ReverseMask = ReverseMask >> 1;
107 Len++;
108 }
109
110 return (UINT8) (32 - Len);
111 }
112
113
114 /**
115 Convert the hexadecimal encoded LUN string into the 64-bit LUN.
116
117 @param[in] Str The hexadecimal encoded LUN string.
118 @param[out] Lun Storage to return the 64-bit LUN.
119
120 @retval EFI_SUCCESS The 64-bit LUN is stored in Lun.
121 @retval EFI_INVALID_PARAMETER The string is malformatted.
122
123 **/
124 EFI_STATUS
125 IScsiAsciiStrToLun (
126 IN CHAR8 *Str,
127 OUT UINT8 *Lun
128 )
129 {
130 UINTN Index, IndexValue, IndexNum, SizeStr;
131 CHAR8 TemStr[2];
132 UINT8 TemValue;
133 UINT16 Value[4];
134
135 ZeroMem (Lun, 8);
136 ZeroMem (TemStr, 2);
137 ZeroMem ((UINT8 *) Value, sizeof (Value));
138 SizeStr = AsciiStrLen (Str);
139 IndexValue = 0;
140 IndexNum = 0;
141
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)) {
147 //
148 // Invalid Lun Char.
149 //
150 return EFI_INVALID_PARAMETER;
151 }
152 }
153
154 if ((TemValue == 0) && (TemStr[0] == '-')) {
155 //
156 // Next Lun value.
157 //
158 if (++IndexValue >= 4) {
159 //
160 // Max 4 Lun value.
161 //
162 return EFI_INVALID_PARAMETER;
163 }
164 //
165 // Restart str index for the next lun value.
166 //
167 IndexNum = 0;
168 continue;
169 }
170
171 if (++IndexNum > 4) {
172 //
173 // Each Lun Str can't exceed size 4, because it will be as UINT16 value.
174 //
175 return EFI_INVALID_PARAMETER;
176 }
177
178 //
179 // Combine UINT16 value.
180 //
181 Value[IndexValue] = (UINT16) ((Value[IndexValue] << 4) + TemValue);
182 }
183
184 for (Index = 0; Index <= IndexValue; Index ++) {
185 *((UINT16 *) &Lun[Index * 2]) = HTONS (Value[Index]);
186 }
187
188 return EFI_SUCCESS;
189 }
190
191 /**
192 Convert the 64-bit LUN into the hexadecimal encoded LUN string.
193
194 @param[in] Lun The 64-bit LUN.
195 @param[out] Str The storage to return the hexadecimal encoded LUN string.
196
197 **/
198 VOID
199 IScsiLunToUnicodeStr (
200 IN UINT8 *Lun,
201 OUT CHAR16 *Str
202 )
203 {
204 UINTN Index;
205 CHAR16 *TempStr;
206
207 TempStr = Str;
208
209 for (Index = 0; Index < 4; Index++) {
210
211 if ((Lun[2 * Index] | Lun[2 * Index + 1]) == 0) {
212 CopyMem (TempStr, L"0-", sizeof (L"0-"));
213 } else {
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];
218 TempStr[4] = L'-';
219 TempStr[5] = 0;
220
221 IScsiStrTrim (TempStr, L'0');
222 }
223
224 TempStr += StrLen (TempStr);
225 }
226 //
227 // Remove the last '-'
228 //
229 ASSERT (StrLen(Str) >= 1);
230 Str[StrLen (Str) - 1] = 0;
231
232 for (Index = StrLen (Str) - 1; Index > 1; Index = Index - 2) {
233 if ((Str[Index] == L'0') && (Str[Index - 1] == L'-')) {
234 Str[Index - 1] = 0;
235 } else {
236 break;
237 }
238 }
239 }
240
241 /**
242 Convert the formatted IP address into the binary IP address.
243
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.
247
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
250 invalid.
251
252 **/
253 EFI_STATUS
254 IScsiAsciiStrToIp (
255 IN CHAR8 *Str,
256 IN UINT8 IpMode,
257 OUT EFI_IP_ADDRESS *Ip
258 )
259 {
260 EFI_STATUS Status;
261
262 if (IpMode == IP_MODE_IP4 || IpMode == IP_MODE_AUTOCONFIG_IP4) {
263 return NetLibAsciiStrToIp4 (Str, &Ip->v4);
264
265 } else if (IpMode == IP_MODE_IP6 || IpMode == IP_MODE_AUTOCONFIG_IP6) {
266 return NetLibAsciiStrToIp6 (Str, &Ip->v6);
267
268 } else if (IpMode == IP_MODE_AUTOCONFIG) {
269 Status = NetLibAsciiStrToIp4 (Str, &Ip->v4);
270 if (!EFI_ERROR (Status)) {
271 return Status;
272 }
273 return NetLibAsciiStrToIp6 (Str, &Ip->v6);
274
275 }
276
277 return EFI_INVALID_PARAMETER;
278 }
279
280 /**
281 Convert the mac address into a hexadecimal encoded "-" seperated string.
282
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.
287
288 **/
289 VOID
290 IScsiMacAddrToStr (
291 IN EFI_MAC_ADDRESS *Mac,
292 IN UINT32 Len,
293 IN UINT16 VlanId,
294 OUT CHAR16 *Str
295 )
296 {
297 UINT32 Index;
298 CHAR16 *String;
299
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':';
304 }
305
306 String = &Str[3 * Index - 1] ;
307 if (VlanId != 0) {
308 String += UnicodeSPrint (String, 6 * sizeof (CHAR16), L"\\%04x", (UINTN) VlanId);
309 }
310
311 *String = L'\0';
312 }
313
314 /**
315 Convert the binary encoded buffer into a hexadecimal encoded string.
316
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.
321
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.
326
327 **/
328 EFI_STATUS
329 IScsiBinToHex (
330 IN UINT8 *BinBuffer,
331 IN UINT32 BinLength,
332 IN OUT CHAR8 *HexStr,
333 IN OUT UINT32 *HexLength
334 )
335 {
336 UINTN Index;
337
338 if ((HexStr == NULL) || (BinBuffer == NULL) || (BinLength == 0)) {
339 return EFI_INVALID_PARAMETER;
340 }
341
342 if (((*HexLength) - 3) < BinLength * 2) {
343 *HexLength = BinLength * 2 + 3;
344 return EFI_BUFFER_TOO_SMALL;
345 }
346
347 *HexLength = BinLength * 2 + 3;
348 //
349 // Prefix for Hex String.
350 //
351 HexStr[0] = '0';
352 HexStr[1] = 'x';
353
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];
357 }
358
359 HexStr[Index * 2 + 2] = '\0';
360
361 return EFI_SUCCESS;
362 }
363
364
365 /**
366 Convert the hexadecimal string into a binary encoded buffer.
367
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.
371
372 @retval EFI_SUCCESS The hexadecimal string is converted into a binary
373 encoded buffer.
374 @retval EFI_BUFFER_TOO_SMALL The binary buffer is too small to hold the converted data.
375
376 **/
377 EFI_STATUS
378 IScsiHexToBin (
379 IN OUT UINT8 *BinBuffer,
380 IN OUT UINT32 *BinLength,
381 IN CHAR8 *HexStr
382 )
383 {
384 UINTN Index;
385 UINTN Length;
386 UINT8 Digit;
387 CHAR8 TemStr[2];
388
389 ZeroMem (TemStr, sizeof (TemStr));
390
391 //
392 // Find out how many hex characters the string has.
393 //
394 if ((HexStr[0] == '0') && ((HexStr[1] == 'x') || (HexStr[1] == 'X'))) {
395 HexStr += 2;
396 }
397
398 Length = AsciiStrLen (HexStr);
399
400 for (Index = 0; Index < Length; Index ++) {
401 TemStr[0] = HexStr[Index];
402 Digit = (UINT8) AsciiStrHexToUint64 (TemStr);
403 if (Digit == 0 && TemStr[0] != '0') {
404 //
405 // Invalid Lun Char.
406 //
407 break;
408 }
409 if ((Index & 1) == 0) {
410 BinBuffer [Index/2] = Digit;
411 } else {
412 BinBuffer [Index/2] = (UINT8) ((BinBuffer [Index/2] << 4) + Digit);
413 }
414 }
415
416 *BinLength = (UINT32) ((Index + 1)/2);
417
418 return EFI_SUCCESS;
419 }
420
421
422 /**
423 Convert the decimal-constant string or hex-constant string into a numerical value.
424
425 @param[in] Str String in decimal or hex.
426
427 @return The numerical value.
428
429 **/
430 UINTN
431 IScsiNetNtoi (
432 IN CHAR8 *Str
433 )
434 {
435 if ((Str[0] == '0') && ((Str[1] == 'x') || (Str[1] == 'X'))) {
436 Str += 2;
437
438 return AsciiStrHexToUintn (Str);
439 }
440
441 return AsciiStrDecimalToUintn (Str);
442 }
443
444
445 /**
446 Generate random numbers.
447
448 @param[in, out] Rand The buffer to contain random numbers.
449 @param[in] RandLength The length of the Rand buffer.
450
451 **/
452 VOID
453 IScsiGenRandom (
454 IN OUT UINT8 *Rand,
455 IN UINTN RandLength
456 )
457 {
458 UINT32 Random;
459
460 while (RandLength > 0) {
461 Random = NET_RANDOM (NetRandomInitSeed ());
462 *Rand++ = (UINT8) (Random);
463 RandLength--;
464 }
465 }
466
467
468 /**
469 Check whether UNDI protocol supports IPv6.
470
471 @param[in] ControllerHandle Controller handle.
472 @param[in] Image Handle of the image.
473 @param[out] Ipv6Support TRUE if UNDI supports IPv6.
474
475 @retval EFI_SUCCESS Get the result whether UNDI supports IPv6 by NII or AIP protocol successfully.
476 @retval EFI_NOT_FOUND Don't know whether UNDI supports IPv6 since NII or AIP is not available.
477
478 **/
479 EFI_STATUS
480 IScsiCheckIpv6Support (
481 IN EFI_HANDLE ControllerHandle,
482 IN EFI_HANDLE Image,
483 OUT BOOLEAN *Ipv6Support
484 )
485 {
486 EFI_HANDLE Handle;
487 EFI_ADAPTER_INFORMATION_PROTOCOL *Aip;
488 EFI_STATUS Status;
489 EFI_GUID *InfoTypesBuffer;
490 UINTN InfoTypeBufferCount;
491 UINTN TypeIndex;
492 BOOLEAN Supported;
493 VOID *InfoBlock;
494 UINTN InfoBlockSize;
495
496 EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii;
497
498 ASSERT (Ipv6Support != NULL);
499
500 //
501 // Check whether the UNDI supports IPv6 by NII protocol.
502 //
503 Status = gBS->OpenProtocol (
504 ControllerHandle,
505 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
506 (VOID **) &Nii,
507 Image,
508 ControllerHandle,
509 EFI_OPEN_PROTOCOL_GET_PROTOCOL
510 );
511 if (Status == EFI_SUCCESS) {
512 *Ipv6Support = Nii->Ipv6Supported;
513 return EFI_SUCCESS;
514 }
515
516 //
517 // Get the NIC handle by SNP protocol.
518 //
519 Handle = NetLibGetSnpHandle (ControllerHandle, NULL);
520 if (Handle == NULL) {
521 return EFI_NOT_FOUND;
522 }
523
524 Aip = NULL;
525 Status = gBS->HandleProtocol (
526 Handle,
527 &gEfiAdapterInformationProtocolGuid,
528 (VOID *) &Aip
529 );
530 if (EFI_ERROR (Status) || Aip == NULL) {
531 return EFI_NOT_FOUND;
532 }
533
534 InfoTypesBuffer = NULL;
535 InfoTypeBufferCount = 0;
536 Status = Aip->GetSupportedTypes (Aip, &InfoTypesBuffer, &InfoTypeBufferCount);
537 if (EFI_ERROR (Status) || InfoTypesBuffer == NULL) {
538 FreePool (InfoTypesBuffer);
539 return EFI_NOT_FOUND;
540 }
541
542 Supported = FALSE;
543 for (TypeIndex = 0; TypeIndex < InfoTypeBufferCount; TypeIndex++) {
544 if (CompareGuid (&InfoTypesBuffer[TypeIndex], &gEfiAdapterInfoUndiIpv6SupportGuid)) {
545 Supported = TRUE;
546 break;
547 }
548 }
549
550 FreePool (InfoTypesBuffer);
551 if (!Supported) {
552 return EFI_NOT_FOUND;
553 }
554
555 //
556 // We now have adapter information block.
557 //
558 InfoBlock = NULL;
559 InfoBlockSize = 0;
560 Status = Aip->GetInformation (Aip, &gEfiAdapterInfoUndiIpv6SupportGuid, &InfoBlock, &InfoBlockSize);
561 if (EFI_ERROR (Status) || InfoBlock == NULL) {
562 FreePool (InfoBlock);
563 return EFI_NOT_FOUND;
564 }
565
566 *Ipv6Support = ((EFI_ADAPTER_INFO_UNDI_IPV6_SUPPORT *) InfoBlock)->Ipv6Support;
567 FreePool (InfoBlock);
568
569 return EFI_SUCCESS;
570 }
571
572 /**
573 Record the NIC info in global structure.
574
575 @param[in] Controller The handle of the controller.
576 @param[in] Image Handle of the image.
577
578 @retval EFI_SUCCESS The operation is completed.
579 @retval EFI_OUT_OF_RESOURCES Do not have sufficient resources to finish this
580 operation.
581
582 **/
583 EFI_STATUS
584 IScsiAddNic (
585 IN EFI_HANDLE Controller,
586 IN EFI_HANDLE Image
587 )
588 {
589 EFI_STATUS Status;
590 ISCSI_NIC_INFO *NicInfo;
591 LIST_ENTRY *Entry;
592 EFI_MAC_ADDRESS MacAddr;
593 UINTN HwAddressSize;
594 UINT16 VlanId;
595
596 //
597 // Get MAC address of this network device.
598 //
599 Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);
600 if (EFI_ERROR (Status)) {
601 return Status;
602 }
603
604 //
605 // Get VLAN ID of this network device.
606 //
607 VlanId = NetLibGetVlanId (Controller);
608
609 //
610 // Check whether the NIC info already exists. Return directly if so.
611 //
612 NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
613 NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
614 if (NicInfo->HwAddressSize == HwAddressSize &&
615 CompareMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize) == 0 &&
616 NicInfo->VlanId == VlanId) {
617 mPrivate->CurrentNic = NicInfo->NicIndex;
618
619 //
620 // Set IPv6 available flag.
621 //
622 Status = IScsiCheckIpv6Support (Controller, Image, &NicInfo->Ipv6Available);
623 if (EFI_ERROR (Status)) {
624 //
625 // Fail to get the data whether UNDI supports IPv6.
626 // Set default value to TRUE.
627 //
628 NicInfo->Ipv6Available = TRUE;
629 }
630
631 return EFI_SUCCESS;
632 }
633
634 if (mPrivate->MaxNic < NicInfo->NicIndex) {
635 mPrivate->MaxNic = NicInfo->NicIndex;
636 }
637 }
638
639 //
640 // Record the NIC info in private structure.
641 //
642 NicInfo = AllocateZeroPool (sizeof (ISCSI_NIC_INFO));
643 if (NicInfo == NULL) {
644 return EFI_OUT_OF_RESOURCES;
645 }
646
647 CopyMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize);
648 NicInfo->HwAddressSize = (UINT32) HwAddressSize;
649 NicInfo->VlanId = VlanId;
650 NicInfo->NicIndex = (UINT8) (mPrivate->MaxNic + 1);
651 mPrivate->MaxNic = NicInfo->NicIndex;
652
653 //
654 // Set IPv6 available flag.
655 //
656 Status = IScsiCheckIpv6Support (Controller, Image, &NicInfo->Ipv6Available);
657 if (EFI_ERROR (Status)) {
658 //
659 // Fail to get the data whether UNDI supports IPv6.
660 // Set default value to TRUE.
661 //
662 NicInfo->Ipv6Available = TRUE;
663 }
664
665 //
666 // Get the PCI location.
667 //
668 IScsiGetNICPciLocation (
669 Controller,
670 &NicInfo->BusNumber,
671 &NicInfo->DeviceNumber,
672 &NicInfo->FunctionNumber
673 );
674
675 InsertTailList (&mPrivate->NicInfoList, &NicInfo->Link);
676 mPrivate->NicCount++;
677
678 mPrivate->CurrentNic = NicInfo->NicIndex;
679 return EFI_SUCCESS;
680 }
681
682
683 /**
684 Delete the recorded NIC info from global structure. Also delete corresponding
685 attempts.
686
687 @param[in] Controller The handle of the controller.
688
689 @retval EFI_SUCCESS The operation is completed.
690 @retval EFI_NOT_FOUND The NIC info to be deleted is not recorded.
691
692 **/
693 EFI_STATUS
694 IScsiRemoveNic (
695 IN EFI_HANDLE Controller
696 )
697 {
698 EFI_STATUS Status;
699 ISCSI_NIC_INFO *NicInfo;
700 LIST_ENTRY *Entry;
701 LIST_ENTRY *NextEntry;
702 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
703 ISCSI_NIC_INFO *ThisNic;
704 EFI_MAC_ADDRESS MacAddr;
705 UINTN HwAddressSize;
706 UINT16 VlanId;
707
708 //
709 // Get MAC address of this network device.
710 //
711 Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);
712 if (EFI_ERROR (Status)) {
713 return Status;
714 }
715
716 //
717 // Get VLAN ID of this network device.
718 //
719 VlanId = NetLibGetVlanId (Controller);
720
721 //
722 // Check whether the NIC information exists.
723 //
724 ThisNic = NULL;
725
726 NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
727 NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
728 if (NicInfo->HwAddressSize == HwAddressSize &&
729 CompareMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize) == 0 &&
730 NicInfo->VlanId == VlanId) {
731
732 ThisNic = NicInfo;
733 break;
734 }
735 }
736
737 if (ThisNic == NULL) {
738 return EFI_NOT_FOUND;
739 }
740
741 mPrivate->CurrentNic = ThisNic->NicIndex;
742
743 RemoveEntryList (&ThisNic->Link);
744 FreePool (ThisNic);
745 mPrivate->NicCount--;
746
747 //
748 // Remove all attempts related to this NIC.
749 //
750 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mPrivate->AttemptConfigs) {
751 AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
752 if (AttemptConfigData->NicIndex == mPrivate->CurrentNic) {
753 RemoveEntryList (&AttemptConfigData->Link);
754 mPrivate->AttemptCount--;
755
756 if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO && mPrivate->MpioCount > 0) {
757 if (--mPrivate->MpioCount == 0) {
758 mPrivate->EnableMpio = FALSE;
759 }
760
761 if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB && mPrivate->Krb5MpioCount > 0) {
762 mPrivate->Krb5MpioCount--;
763 }
764
765 } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED && mPrivate->SinglePathCount > 0) {
766 mPrivate->SinglePathCount--;
767
768 if (mPrivate->ValidSinglePathCount > 0) {
769 mPrivate->ValidSinglePathCount--;
770 }
771 }
772
773 FreePool (AttemptConfigData);
774 }
775 }
776
777 return EFI_SUCCESS;
778 }
779
780 /**
781 Create and initialize the Attempts.
782
783 @param[in] AttemptNum The number of Attempts will be created.
784
785 @retval EFI_SUCCESS The Attempts have been created successfully.
786 @retval Others Failed to create the Attempt.
787
788 **/
789 EFI_STATUS
790 IScsiCreateAttempts (
791 IN UINTN AttemptNum
792 )
793 {
794 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
795 ISCSI_SESSION_CONFIG_NVDATA *ConfigData;
796 UINT8 *AttemptConfigOrder;
797 UINTN AttemptConfigOrderSize;
798 UINT8 *AttemptOrderTmp;
799 UINTN TotalNumber;
800 UINT8 Index;
801 EFI_STATUS Status;
802
803 for (Index = 1; Index <= AttemptNum; Index ++) {
804 //
805 // Get the initialized attempt order. This is used to essure creating attempts by order.
806 //
807 AttemptConfigOrder = IScsiGetVariableAndSize (
808 L"InitialAttemptOrder",
809 &gIScsiConfigGuid,
810 &AttemptConfigOrderSize
811 );
812 TotalNumber = AttemptConfigOrderSize / sizeof (UINT8);
813 if (TotalNumber == AttemptNum) {
814 Status = EFI_SUCCESS;
815 break;
816 }
817 TotalNumber++;
818
819 //
820 // Append the new created attempt to the end.
821 //
822 AttemptOrderTmp = AllocateZeroPool (TotalNumber * sizeof (UINT8));
823 if (AttemptOrderTmp == NULL) {
824 if (AttemptConfigOrder != NULL) {
825 FreePool (AttemptConfigOrder);
826 }
827 return EFI_OUT_OF_RESOURCES;
828 }
829
830 if (AttemptConfigOrder != NULL) {
831 CopyMem (AttemptOrderTmp, AttemptConfigOrder, AttemptConfigOrderSize);
832 FreePool (AttemptConfigOrder);
833 }
834
835 AttemptOrderTmp[TotalNumber - 1] = Index;
836 AttemptConfigOrder = AttemptOrderTmp;
837 AttemptConfigOrderSize = TotalNumber * sizeof (UINT8);
838
839 Status = gRT->SetVariable (
840 L"InitialAttemptOrder",
841 &gIScsiConfigGuid,
842 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
843 AttemptConfigOrderSize,
844 AttemptConfigOrder
845 );
846 FreePool (AttemptConfigOrder);
847 if (EFI_ERROR (Status)) {
848 return Status;
849 }
850
851 //
852 // Create new Attempt
853 //
854 AttemptConfigData = AllocateZeroPool (sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA));
855 if (AttemptConfigData == NULL) {
856 return EFI_OUT_OF_RESOURCES;
857 }
858 ConfigData = &AttemptConfigData->SessionConfigData;
859 ConfigData->TargetPort = ISCSI_WELL_KNOWN_PORT;
860 ConfigData->ConnectTimeout = CONNECT_DEFAULT_TIMEOUT;
861 ConfigData->ConnectRetryCount = CONNECT_MIN_RETRY;
862
863 AttemptConfigData->AuthenticationType = ISCSI_AUTH_TYPE_CHAP;
864 AttemptConfigData->AuthConfigData.CHAP.CHAPType = ISCSI_CHAP_UNI;
865 //
866 // Configure the Attempt index and set variable.
867 //
868 AttemptConfigData->AttemptConfigIndex = Index;
869
870 //
871 // Set the attempt name according to the order.
872 //
873 UnicodeSPrint (
874 mPrivate->PortString,
875 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
876 L"Attempt %d",
877 (UINTN) AttemptConfigData->AttemptConfigIndex
878 );
879 UnicodeStrToAsciiStrS (mPrivate->PortString, AttemptConfigData->AttemptName, ATTEMPT_NAME_SIZE);
880
881 Status = gRT->SetVariable (
882 mPrivate->PortString,
883 &gEfiIScsiInitiatorNameProtocolGuid,
884 ISCSI_CONFIG_VAR_ATTR,
885 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
886 AttemptConfigData
887 );
888 FreePool (AttemptConfigData);
889 if (EFI_ERROR (Status)) {
890 return Status;
891 }
892 }
893
894 return EFI_SUCCESS;
895 }
896
897 /**
898 Create the iSCSI configuration Keywords for each attempt. You can find the keywords
899 defined in the "x-UEFI-ns" namespace (http://www.uefi.org/confignamespace).
900
901 @param[in] KeywordNum The number Sets of Keywords will be created.
902
903 @retval EFI_SUCCESS The operation is completed.
904 @retval Others Failed to create the Keywords.
905
906 **/
907 EFI_STATUS
908 IScsiCreateKeywords (
909 IN UINTN KeywordNum
910 )
911 {
912 VOID *StartOpCodeHandle;
913 EFI_IFR_GUID_LABEL *StartLabel;
914 VOID *EndOpCodeHandle;
915 EFI_IFR_GUID_LABEL *EndLabel;
916 UINTN Index;
917 EFI_STRING_ID StringToken;
918 CHAR16 StringId[64];
919 CHAR16 KeywordId[32];
920 EFI_STATUS Status;
921
922 Status = IScsiCreateOpCode (
923 KEYWORD_ENTRY_LABEL,
924 &StartOpCodeHandle,
925 &StartLabel,
926 &EndOpCodeHandle,
927 &EndLabel
928 );
929 if (EFI_ERROR (Status)) {
930 return EFI_OUT_OF_RESOURCES;
931 }
932
933 for (Index = 1; Index <= KeywordNum; Index ++) {
934 //
935 // Create iSCSIAttemptName Keyword.
936 //
937 UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_ATTEMPTT_NAME_PROMPT%d", Index);
938 StringToken = HiiSetString (
939 mCallbackInfo->RegisteredHandle,
940 0,
941 StringId,
942 NULL
943 );
944 UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIAttemptName:%d", Index);
945 HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns");
946 HiiCreateStringOpCode (
947 StartOpCodeHandle,
948 (EFI_QUESTION_ID) (ATTEMPT_ATTEMPT_NAME_QUESTION_ID + (Index - 1)),
949 CONFIGURATION_VARSTORE_ID,
950 (UINT16) (ATTEMPT_ATTEMPT_NAME_VAR_OFFSET + ATTEMPT_NAME_SIZE * (Index - 1) * sizeof (CHAR16)),
951 StringToken,
952 StringToken,
953 EFI_IFR_FLAG_READ_ONLY,
954 0,
955 0,
956 ATTEMPT_NAME_SIZE,
957 NULL
958 );
959
960 //
961 // Create iSCSIBootEnable Keyword.
962 //
963 UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_MODE_PROMPT%d", Index);
964 StringToken = HiiSetString (
965 mCallbackInfo->RegisteredHandle,
966 0,
967 StringId,
968 NULL
969 );
970 UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIBootEnable:%d", Index);
971 HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns");
972 HiiCreateNumericOpCode (
973 StartOpCodeHandle,
974 (EFI_QUESTION_ID) (ATTEMPT_BOOTENABLE_QUESTION_ID + (Index - 1)),
975 CONFIGURATION_VARSTORE_ID,
976 (UINT16) (ATTEMPT_BOOTENABLE_VAR_OFFSET + (Index - 1)),
977 StringToken,
978 StringToken,
979 0,
980 EFI_IFR_NUMERIC_SIZE_1,
981 0,
982 2,
983 0,
984 NULL
985 );
986
987 //
988 // Create iSCSIIpAddressType Keyword.
989 //
990 UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_IP_MODE_PROMPT%d", Index);
991 StringToken = HiiSetString (
992 mCallbackInfo->RegisteredHandle,
993 0,
994 StringId,
995 NULL
996 );
997 UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIIpAddressType:%d", Index);
998 HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns");
999 HiiCreateNumericOpCode (
1000 StartOpCodeHandle,
1001 (EFI_QUESTION_ID) (ATTEMPT_ADDRESS_TYPE_QUESTION_ID + (Index - 1)),
1002 CONFIGURATION_VARSTORE_ID,
1003 (UINT16) (ATTEMPT_ADDRESS_TYPE_VAR_OFFSET + (Index - 1)),
1004 StringToken,
1005 StringToken,
1006 0,
1007 EFI_IFR_NUMERIC_SIZE_1,
1008 0,
1009 2,
1010 0,
1011 NULL
1012 );
1013
1014 //
1015 // Create iSCSIConnectRetry Keyword.
1016 //
1017 UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_CONNECT_RETRY_PROMPT%d", Index);
1018 StringToken = HiiSetString (
1019 mCallbackInfo->RegisteredHandle,
1020 0,
1021 StringId,
1022 NULL
1023 );
1024 UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIConnectRetry:%d", Index);
1025 HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns");
1026 HiiCreateNumericOpCode (
1027 StartOpCodeHandle,
1028 (EFI_QUESTION_ID) (ATTEMPT_CONNECT_RETRY_QUESTION_ID + (Index - 1)),
1029 CONFIGURATION_VARSTORE_ID,
1030 (UINT16) (ATTEMPT_CONNECT_RETRY_VAR_OFFSET + (Index - 1)),
1031 StringToken,
1032 StringToken,
1033 0,
1034 EFI_IFR_NUMERIC_SIZE_1,
1035 0,
1036 16,
1037 0,
1038 NULL
1039 );
1040
1041 //
1042 // Create iSCSIConnectTimeout Keyword.
1043 //
1044 UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_CONNECT_TIMEOUT_PROMPT%d", Index);
1045 StringToken = HiiSetString (
1046 mCallbackInfo->RegisteredHandle,
1047 0,
1048 StringId,
1049 NULL
1050 );
1051 UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIConnectTimeout:%d", Index);
1052 HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns");
1053 HiiCreateNumericOpCode (
1054 StartOpCodeHandle,
1055 (EFI_QUESTION_ID) (ATTEMPT_CONNECT_TIMEOUT_QUESTION_ID + (Index - 1)),
1056 CONFIGURATION_VARSTORE_ID,
1057 (UINT16) (ATTEMPT_CONNECT_TIMEOUT_VAR_OFFSET + 2 * (Index - 1)),
1058 StringToken,
1059 StringToken,
1060 0,
1061 EFI_IFR_NUMERIC_SIZE_2,
1062 CONNECT_MIN_TIMEOUT,
1063 CONNECT_MAX_TIMEOUT,
1064 0,
1065 NULL
1066 );
1067
1068 //
1069 // Create ISID Keyword.
1070 //
1071 UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_ISID_PROMPT%d", Index);
1072 StringToken = HiiSetString (
1073 mCallbackInfo->RegisteredHandle,
1074 0,
1075 StringId,
1076 NULL
1077 );
1078 UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIISID:%d", Index);
1079 HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns");
1080 HiiCreateStringOpCode (
1081 StartOpCodeHandle,
1082 (EFI_QUESTION_ID) (ATTEMPT_ISID_QUESTION_ID + (Index - 1)),
1083 CONFIGURATION_VARSTORE_ID,
1084 (UINT16) (ATTEMPT_ISID_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)),
1085 StringToken,
1086 STRING_TOKEN (STR_ISCSI_ISID_HELP),
1087 0,
1088 0,
1089 ISID_CONFIGURABLE_MIN_LEN,
1090 ISID_CONFIGURABLE_STORAGE,
1091 NULL
1092 );
1093
1094 //
1095 // Create iSCSIInitiatorInfoViaDHCP Keyword.
1096 //
1097 UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_INITIATOR_VIA_DHCP_PROMPT%d", Index);
1098 StringToken = HiiSetString (
1099 mCallbackInfo->RegisteredHandle,
1100 0,
1101 StringId,
1102 NULL
1103 );
1104 UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIInitiatorInfoViaDHCP:%d", Index);
1105 HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns");
1106 HiiCreateNumericOpCode (
1107 StartOpCodeHandle,
1108 (EFI_QUESTION_ID) (ATTEMPT_INITIATOR_VIA_DHCP_QUESTION_ID + (Index - 1)),
1109 CONFIGURATION_VARSTORE_ID,
1110 (UINT16) (ATTEMPT_INITIATOR_VIA_DHCP_VAR_OFFSET + (Index - 1)),
1111 StringToken,
1112 StringToken,
1113 0,
1114 0,
1115 0,
1116 1,
1117 0,
1118 NULL
1119 );
1120
1121 //
1122 // Create iSCSIInitiatorIpAddress Keyword.
1123 //
1124 UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_INITIATOR_IP_ADDRESS_PROMPT%d", Index);
1125 StringToken = HiiSetString (
1126 mCallbackInfo->RegisteredHandle,
1127 0,
1128 StringId,
1129 NULL
1130 );
1131 UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIInitiatorIpAddress:%d", Index);
1132 HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns");
1133 HiiCreateStringOpCode (
1134 StartOpCodeHandle,
1135 (EFI_QUESTION_ID) (ATTEMPT_INITIATOR_IP_ADDRESS_QUESTION_ID + (Index - 1)),
1136 CONFIGURATION_VARSTORE_ID,
1137 (UINT16) (ATTEMPT_INITIATOR_IP_ADDRESS_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)),
1138 StringToken,
1139 StringToken,
1140 0,
1141 0,
1142 IP4_MIN_SIZE,
1143 IP4_STR_MAX_SIZE,
1144 NULL
1145 );
1146
1147 //
1148 // Create iSCSIInitiatorNetmask Keyword.
1149 //
1150 UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_INITIATOR_NET_MASK_PROMPT%d", Index);
1151 StringToken = HiiSetString (
1152 mCallbackInfo->RegisteredHandle,
1153 0,
1154 StringId,
1155 NULL
1156 );
1157 UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIInitiatorNetmask:%d", Index);
1158 HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns");
1159 HiiCreateStringOpCode (
1160 StartOpCodeHandle,
1161 (EFI_QUESTION_ID) (ATTEMPT_INITIATOR_NET_MASK_QUESTION_ID + (Index - 1)),
1162 CONFIGURATION_VARSTORE_ID,
1163 (UINT16) (ATTEMPT_INITIATOR_NET_MASK_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)),
1164 StringToken,
1165 StringToken,
1166 0,
1167 0,
1168 IP4_MIN_SIZE,
1169 IP4_STR_MAX_SIZE,
1170 NULL
1171 );
1172
1173 //
1174 // Create iSCSIInitiatorGateway Keyword.
1175 //
1176 UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_INITIATOR_GATE_PROMPT%d", Index);
1177 StringToken = HiiSetString (
1178 mCallbackInfo->RegisteredHandle,
1179 0,
1180 StringId,
1181 NULL
1182 );
1183 UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIInitiatorGateway:%d", Index);
1184 HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns");
1185 HiiCreateStringOpCode (
1186 StartOpCodeHandle,
1187 (EFI_QUESTION_ID) (ATTEMPT_INITIATOR_GATE_WAY_QUESTION_ID + (Index - 1)),
1188 CONFIGURATION_VARSTORE_ID,
1189 (UINT16) (ATTEMPT_INITIATOR_GATE_WAY_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)),
1190 StringToken,
1191 StringToken,
1192 0,
1193 0,
1194 IP4_MIN_SIZE,
1195 IP4_STR_MAX_SIZE,
1196 NULL
1197 );
1198
1199 //
1200 // Create iSCSITargetInfoViaDHCP Keyword.
1201 //
1202 UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_TARGET_VIA_DHCP_PROMPT%d", Index);
1203 StringToken = HiiSetString (
1204 mCallbackInfo->RegisteredHandle,
1205 0,
1206 StringId,
1207 NULL
1208 );
1209 UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSITargetInfoViaDHCP:%d", Index);
1210 HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns");
1211 HiiCreateNumericOpCode (
1212 StartOpCodeHandle,
1213 (EFI_QUESTION_ID) (ATTEMPT_TARGET_VIA_DHCP_QUESTION_ID + (Index - 1)),
1214 CONFIGURATION_VARSTORE_ID,
1215 (UINT16) (ATTEMPT_TARGET_VIA_DHCP_VAR_OFFSET + (Index - 1)),
1216 StringToken,
1217 StringToken,
1218 0,
1219 0,
1220 0,
1221 1,
1222 0,
1223 NULL
1224 );
1225
1226 //
1227 // Create iSCSITargetTcpPort Keyword.
1228 //
1229 UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_TARGET_TCP_PORT_PROMPT%d", Index);
1230 StringToken = HiiSetString (
1231 mCallbackInfo->RegisteredHandle,
1232 0,
1233 StringId,
1234 NULL
1235 );
1236 UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSITargetTcpPort:%d", Index);
1237 HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns");
1238 HiiCreateNumericOpCode (
1239 StartOpCodeHandle,
1240 (EFI_QUESTION_ID) (ATTEMPT_TARGET_TCP_PORT_QUESTION_ID + (Index - 1)),
1241 CONFIGURATION_VARSTORE_ID,
1242 (UINT16) (ATTEMPT_TARGET_TCP_PORT_VAR_OFFSET + 2 * (Index - 1)),
1243 StringToken,
1244 StringToken,
1245 0,
1246 EFI_IFR_NUMERIC_SIZE_2,
1247 TARGET_PORT_MIN_NUM,
1248 TARGET_PORT_MAX_NUM,
1249 0,
1250 NULL
1251 );
1252
1253 //
1254 // Create iSCSITargetName Keyword.
1255 //
1256 UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_TARGET_NAME_PROMPT%d", Index);
1257 StringToken = HiiSetString (
1258 mCallbackInfo->RegisteredHandle,
1259 0,
1260 StringId,
1261 NULL
1262 );
1263 UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSITargetName:%d", Index);
1264 HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns");
1265 HiiCreateStringOpCode (
1266 StartOpCodeHandle,
1267 (EFI_QUESTION_ID) (ATTEMPT_TARGET_NAME_QUESTION_ID + (Index - 1)),
1268 CONFIGURATION_VARSTORE_ID,
1269 (UINT16) (ATTEMPT_TARGET_NAME_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)),
1270 StringToken,
1271 StringToken,
1272 0,
1273 0,
1274 ISCSI_NAME_IFR_MIN_SIZE,
1275 ISCSI_NAME_IFR_MAX_SIZE,
1276 NULL
1277 );
1278
1279 //
1280 // Create iSCSITargetIpAddress Keyword.
1281 //
1282 UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_TARGET_IP_ADDRESS_PROMPT%d", Index);
1283 StringToken = HiiSetString (
1284 mCallbackInfo->RegisteredHandle,
1285 0,
1286 StringId,
1287 NULL
1288 );
1289 UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSITargetIpAddress:%d", Index);
1290 HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns");
1291 HiiCreateStringOpCode (
1292 StartOpCodeHandle,
1293 (EFI_QUESTION_ID) (ATTEMPT_TARGET_IP_ADDRESS_QUESTION_ID + (Index - 1)),
1294 CONFIGURATION_VARSTORE_ID,
1295 (UINT16) (ATTEMPT_TARGET_IP_ADDRESS_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)),
1296 StringToken,
1297 StringToken,
1298 0,
1299 0,
1300 IP_MIN_SIZE,
1301 IP_STR_MAX_SIZE,
1302 NULL
1303 );
1304
1305 //
1306 // Create iSCSILUN Keyword.
1307 //
1308 UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_LUN_PROMPT%d", Index);
1309 StringToken = HiiSetString (
1310 mCallbackInfo->RegisteredHandle,
1311 0,
1312 StringId,
1313 NULL
1314 );
1315 UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSILUN:%d", Index);
1316 HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns");
1317 HiiCreateStringOpCode (
1318 StartOpCodeHandle,
1319 (EFI_QUESTION_ID) (ATTEMPT_LUN_QUESTION_ID + (Index - 1)),
1320 CONFIGURATION_VARSTORE_ID,
1321 (UINT16) (ATTEMPT_LUN_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)),
1322 StringToken,
1323 StringToken,
1324 0,
1325 0,
1326 LUN_MIN_SIZE,
1327 LUN_MAX_SIZE,
1328 NULL
1329 );
1330
1331 //
1332 // Create iSCSIAuthenticationMethod Keyword.
1333 //
1334 UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_AUTHENTICATION_METHOD_PROMPT%d", Index);
1335 StringToken = HiiSetString (
1336 mCallbackInfo->RegisteredHandle,
1337 0,
1338 StringId,
1339 NULL
1340 );
1341 UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIAuthenticationMethod:%d", Index);
1342 HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns");
1343 HiiCreateNumericOpCode (
1344 StartOpCodeHandle,
1345 (EFI_QUESTION_ID) (ATTEMPT_AUTHENTICATION_METHOD_QUESTION_ID + (Index - 1)),
1346 CONFIGURATION_VARSTORE_ID,
1347 (UINT16) (ATTEMPT_AUTHENTICATION_METHOD_VAR_OFFSET + (Index - 1)),
1348 StringToken,
1349 StringToken,
1350 0,
1351 0,
1352 0,
1353 1,
1354 0,
1355 NULL
1356 );
1357
1358 //
1359 // Create iSCSIChapType Keyword.
1360 //
1361 UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_CHARTYPE_PROMPT%d", Index);
1362 StringToken = HiiSetString (
1363 mCallbackInfo->RegisteredHandle,
1364 0,
1365 StringId,
1366 NULL
1367 );
1368 UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIChapType:%d", Index);
1369 HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns");
1370 HiiCreateNumericOpCode (
1371 StartOpCodeHandle,
1372 (EFI_QUESTION_ID) (ATTEMPT_CHARTYPE_QUESTION_ID + (Index - 1)),
1373 CONFIGURATION_VARSTORE_ID,
1374 (UINT16) (ATTEMPT_CHARTYPE_VAR_OFFSET + (Index - 1)),
1375 StringToken,
1376 StringToken,
1377 0,
1378 0,
1379 0,
1380 1,
1381 0,
1382 NULL
1383 );
1384
1385 //
1386 // Create iSCSIChapUsername Keyword.
1387 //
1388 UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_CHAR_USER_NAME_PROMPT%d", Index);
1389 StringToken = HiiSetString (
1390 mCallbackInfo->RegisteredHandle,
1391 0,
1392 StringId,
1393 NULL
1394 );
1395 UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIChapUsername:%d", Index);
1396 HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns");
1397 HiiCreateStringOpCode (
1398 StartOpCodeHandle,
1399 (EFI_QUESTION_ID) (ATTEMPT_CHAR_USER_NAME_QUESTION_ID + (Index - 1)),
1400 CONFIGURATION_VARSTORE_ID,
1401 (UINT16) (ATTEMPT_CHAR_USER_NAME_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)),
1402 StringToken,
1403 StringToken,
1404 0,
1405 0,
1406 0,
1407 ISCSI_CHAP_NAME_MAX_LEN,
1408 NULL
1409 );
1410
1411 //
1412 // Create iSCSIChapSecret Keyword.
1413 //
1414 UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_CHAR_SECRET_PROMPT%d", Index);
1415 StringToken = HiiSetString (
1416 mCallbackInfo->RegisteredHandle,
1417 0,
1418 StringId,
1419 NULL
1420 );
1421 UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIChapSecret:%d", Index);
1422 HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns");
1423 HiiCreateStringOpCode (
1424 StartOpCodeHandle,
1425 (EFI_QUESTION_ID) (ATTEMPT_CHAR_SECRET_QUESTION_ID + (Index - 1)),
1426 CONFIGURATION_VARSTORE_ID,
1427 (UINT16) (ATTEMPT_CHAR_SECRET_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)),
1428 StringToken,
1429 StringToken,
1430 0,
1431 0,
1432 ISCSI_CHAP_SECRET_MIN_LEN,
1433 ISCSI_CHAP_SECRET_MAX_LEN,
1434 NULL
1435 );
1436
1437 //
1438 // Create iSCSIReverseChapUsername Keyword.
1439 //
1440 UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_CHAR_REVERSE_USER_NAME_PROMPT%d", Index);
1441 StringToken = HiiSetString (
1442 mCallbackInfo->RegisteredHandle,
1443 0,
1444 StringId,
1445 NULL
1446 );
1447 UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIReverseChapUsername:%d", Index);
1448 HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns");
1449 HiiCreateStringOpCode (
1450 StartOpCodeHandle,
1451 (EFI_QUESTION_ID) (ATTEMPT_CHAR_REVERSE_USER_NAME_QUESTION_ID + (Index - 1)),
1452 CONFIGURATION_VARSTORE_ID,
1453 (UINT16) (ATTEMPT_CHAR_REVERSE_USER_NAME_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)),
1454 StringToken,
1455 StringToken,
1456 0,
1457 0,
1458 0,
1459 ISCSI_CHAP_NAME_MAX_LEN,
1460 NULL
1461 );
1462
1463 //
1464 // Create iSCSIReverseChapSecret Keyword.
1465 //
1466 UnicodeSPrint (StringId, sizeof (StringId), L"STR_ISCSI_CHAR_REVERSE_SECRET_PROMPT%d", Index);
1467 StringToken = HiiSetString (
1468 mCallbackInfo->RegisteredHandle,
1469 0,
1470 StringId,
1471 NULL
1472 );
1473 UnicodeSPrint (KeywordId, sizeof (KeywordId), L"iSCSIReverseChapSecret:%d", Index);
1474 HiiSetString (mCallbackInfo->RegisteredHandle, StringToken, KeywordId, "x-UEFI-ns");
1475 HiiCreateStringOpCode (
1476 StartOpCodeHandle,
1477 (EFI_QUESTION_ID) (ATTEMPT_CHAR_REVERSE_SECRET_QUESTION_ID + (Index - 1)),
1478 CONFIGURATION_VARSTORE_ID,
1479 (UINT16) (ATTEMPT_CHAR_REVERSE_SECRET_VAR_OFFSET + sizeof (KEYWORD_STR) * (Index - 1)),
1480 StringToken,
1481 StringToken,
1482 0,
1483 0,
1484 ISCSI_CHAP_SECRET_MIN_LEN,
1485 ISCSI_CHAP_SECRET_MAX_LEN,
1486 NULL
1487 );
1488 }
1489
1490 Status = HiiUpdateForm (
1491 mCallbackInfo->RegisteredHandle, // HII handle
1492 &gIScsiConfigGuid, // Formset GUID
1493 FORMID_ATTEMPT_FORM, // Form ID
1494 StartOpCodeHandle, // Label for where to insert opcodes
1495 EndOpCodeHandle // Replace data
1496 );
1497
1498 HiiFreeOpCodeHandle (StartOpCodeHandle);
1499 HiiFreeOpCodeHandle (EndOpCodeHandle);
1500
1501 return Status;
1502 }
1503
1504 /**
1505
1506 Free the attempt configure data variable.
1507
1508 **/
1509 VOID
1510 IScsiCleanAttemptVariable (
1511 IN VOID
1512 )
1513 {
1514 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
1515 UINT8 *AttemptConfigOrder;
1516 UINTN AttemptConfigOrderSize;
1517 UINTN Index;
1518
1519 //
1520 // Get the initialized attempt order.
1521 //
1522 AttemptConfigOrder = IScsiGetVariableAndSize (
1523 L"InitialAttemptOrder",
1524 &gIScsiConfigGuid,
1525 &AttemptConfigOrderSize
1526 );
1527 if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) {
1528 return;
1529 }
1530
1531 for (Index = 1; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
1532 UnicodeSPrint (
1533 mPrivate->PortString,
1534 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
1535 L"Attempt %d",
1536 Index
1537 );
1538
1539 GetVariable2 (
1540 mPrivate->PortString,
1541 &gEfiIScsiInitiatorNameProtocolGuid,
1542 (VOID**)&AttemptConfigData,
1543 NULL
1544 );
1545
1546 if (AttemptConfigData != NULL) {
1547 gRT->SetVariable (
1548 mPrivate->PortString,
1549 &gEfiIScsiInitiatorNameProtocolGuid,
1550 0,
1551 0,
1552 NULL
1553 );
1554 }
1555 }
1556 return;
1557 }
1558
1559 /**
1560 Get the recorded NIC info from global structure by the Index.
1561
1562 @param[in] NicIndex The index indicates the position of NIC info.
1563
1564 @return Pointer to the NIC info, or NULL if not found.
1565
1566 **/
1567 ISCSI_NIC_INFO *
1568 IScsiGetNicInfoByIndex (
1569 IN UINT8 NicIndex
1570 )
1571 {
1572 LIST_ENTRY *Entry;
1573 ISCSI_NIC_INFO *NicInfo;
1574
1575 NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
1576 NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
1577 if (NicInfo->NicIndex == NicIndex) {
1578 return NicInfo;
1579 }
1580 }
1581
1582 return NULL;
1583 }
1584
1585
1586 /**
1587 Get the NIC's PCI location and return it according to the composited
1588 format defined in iSCSI Boot Firmware Table.
1589
1590 @param[in] Controller The handle of the controller.
1591 @param[out] Bus The bus number.
1592 @param[out] Device The device number.
1593 @param[out] Function The function number.
1594
1595 @return The composited representation of the NIC PCI location.
1596
1597 **/
1598 UINT16
1599 IScsiGetNICPciLocation (
1600 IN EFI_HANDLE Controller,
1601 OUT UINTN *Bus,
1602 OUT UINTN *Device,
1603 OUT UINTN *Function
1604 )
1605 {
1606 EFI_STATUS Status;
1607 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1608 EFI_HANDLE PciIoHandle;
1609 EFI_PCI_IO_PROTOCOL *PciIo;
1610 UINTN Segment;
1611
1612 Status = gBS->HandleProtocol (
1613 Controller,
1614 &gEfiDevicePathProtocolGuid,
1615 (VOID **) &DevicePath
1616 );
1617 if (EFI_ERROR (Status)) {
1618 return 0;
1619 }
1620
1621 Status = gBS->LocateDevicePath (
1622 &gEfiPciIoProtocolGuid,
1623 &DevicePath,
1624 &PciIoHandle
1625 );
1626 if (EFI_ERROR (Status)) {
1627 return 0;
1628 }
1629
1630 Status = gBS->HandleProtocol (PciIoHandle, &gEfiPciIoProtocolGuid, (VOID **) &PciIo);
1631 if (EFI_ERROR (Status)) {
1632 return 0;
1633 }
1634
1635 Status = PciIo->GetLocation (PciIo, &Segment, Bus, Device, Function);
1636 if (EFI_ERROR (Status)) {
1637 return 0;
1638 }
1639
1640 return (UINT16) ((*Bus << 8) | (*Device << 3) | *Function);
1641 }
1642
1643
1644 /**
1645 Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
1646 buffer, and the size of the buffer. If failure, return NULL.
1647
1648 @param[in] Name String part of EFI variable name.
1649 @param[in] VendorGuid GUID part of EFI variable name.
1650 @param[out] VariableSize Returns the size of the EFI variable that was read.
1651
1652 @return Dynamically allocated memory that contains a copy of the EFI variable.
1653 @return Caller is responsible freeing the buffer.
1654 @retval NULL Variable was not read.
1655
1656 **/
1657 VOID *
1658 IScsiGetVariableAndSize (
1659 IN CHAR16 *Name,
1660 IN EFI_GUID *VendorGuid,
1661 OUT UINTN *VariableSize
1662 )
1663 {
1664 EFI_STATUS Status;
1665 UINTN BufferSize;
1666 VOID *Buffer;
1667
1668 Buffer = NULL;
1669
1670 //
1671 // Pass in a zero size buffer to find the required buffer size.
1672 //
1673 BufferSize = 0;
1674 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
1675 if (Status == EFI_BUFFER_TOO_SMALL) {
1676 //
1677 // Allocate the buffer to return
1678 //
1679 Buffer = AllocateZeroPool (BufferSize);
1680 if (Buffer == NULL) {
1681 return NULL;
1682 }
1683 //
1684 // Read variable into the allocated buffer.
1685 //
1686 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
1687 if (EFI_ERROR (Status)) {
1688 BufferSize = 0;
1689 }
1690 }
1691
1692 *VariableSize = BufferSize;
1693 return Buffer;
1694 }
1695
1696
1697 /**
1698 Create the iSCSI driver data.
1699
1700 @param[in] Image The handle of the driver image.
1701 @param[in] Controller The handle of the controller.
1702
1703 @return The iSCSI driver data created.
1704 @retval NULL Other errors as indicated.
1705
1706 **/
1707 ISCSI_DRIVER_DATA *
1708 IScsiCreateDriverData (
1709 IN EFI_HANDLE Image,
1710 IN EFI_HANDLE Controller
1711 )
1712 {
1713 ISCSI_DRIVER_DATA *Private;
1714 EFI_STATUS Status;
1715
1716 Private = AllocateZeroPool (sizeof (ISCSI_DRIVER_DATA));
1717 if (Private == NULL) {
1718 return NULL;
1719 }
1720
1721 Private->Signature = ISCSI_DRIVER_DATA_SIGNATURE;
1722 Private->Image = Image;
1723 Private->Controller = Controller;
1724 Private->Session = NULL;
1725
1726 //
1727 // Create an event to be signaled when the BS to RT transition is triggerd so
1728 // as to abort the iSCSI session.
1729 //
1730 Status = gBS->CreateEventEx (
1731 EVT_NOTIFY_SIGNAL,
1732 TPL_CALLBACK,
1733 IScsiOnExitBootService,
1734 Private,
1735 &gEfiEventExitBootServicesGuid,
1736 &Private->ExitBootServiceEvent
1737 );
1738 if (EFI_ERROR (Status)) {
1739 FreePool (Private);
1740 return NULL;
1741 }
1742
1743 Private->ExtScsiPassThruHandle = NULL;
1744 CopyMem(&Private->IScsiExtScsiPassThru, &gIScsiExtScsiPassThruProtocolTemplate, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL));
1745
1746 //
1747 // 0 is designated to the TargetId, so use another value for the AdapterId.
1748 //
1749 Private->ExtScsiPassThruMode.AdapterId = 2;
1750 Private->ExtScsiPassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
1751 Private->ExtScsiPassThruMode.IoAlign = 4;
1752 Private->IScsiExtScsiPassThru.Mode = &Private->ExtScsiPassThruMode;
1753
1754 return Private;
1755 }
1756
1757
1758 /**
1759 Clean the iSCSI driver data.
1760
1761 @param[in] Private The iSCSI driver data.
1762
1763 @retval EFI_SUCCESS The clean operation is successful.
1764 @retval Others Other errors as indicated.
1765
1766 **/
1767 EFI_STATUS
1768 IScsiCleanDriverData (
1769 IN ISCSI_DRIVER_DATA *Private
1770 )
1771 {
1772 EFI_STATUS Status;
1773
1774 Status = EFI_SUCCESS;
1775
1776 if (Private->DevicePath != NULL) {
1777 Status = gBS->UninstallProtocolInterface (
1778 Private->ExtScsiPassThruHandle,
1779 &gEfiDevicePathProtocolGuid,
1780 Private->DevicePath
1781 );
1782 if (EFI_ERROR (Status)) {
1783 goto EXIT;
1784 }
1785
1786 FreePool (Private->DevicePath);
1787 }
1788
1789 if (Private->ExtScsiPassThruHandle != NULL) {
1790 Status = gBS->UninstallProtocolInterface (
1791 Private->ExtScsiPassThruHandle,
1792 &gEfiExtScsiPassThruProtocolGuid,
1793 &Private->IScsiExtScsiPassThru
1794 );
1795 if (!EFI_ERROR (Status)) {
1796 mPrivate->OneSessionEstablished = FALSE;
1797 }
1798 }
1799
1800 EXIT:
1801 if (Private->ExitBootServiceEvent != NULL) {
1802 gBS->CloseEvent (Private->ExitBootServiceEvent);
1803 }
1804
1805 mCallbackInfo->Current = NULL;
1806
1807 FreePool (Private);
1808 return Status;
1809 }
1810
1811 /**
1812 Check wheather the Controller handle is configured to use DHCP protocol.
1813
1814 @param[in] Controller The handle of the controller.
1815 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
1816
1817 @retval TRUE The handle of the controller need the Dhcp protocol.
1818 @retval FALSE The handle of the controller does not need the Dhcp protocol.
1819
1820 **/
1821 BOOLEAN
1822 IScsiDhcpIsConfigured (
1823 IN EFI_HANDLE Controller,
1824 IN UINT8 IpVersion
1825 )
1826 {
1827 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptTmp;
1828 UINT8 *AttemptConfigOrder;
1829 UINTN AttemptConfigOrderSize;
1830 UINTN Index;
1831 EFI_STATUS Status;
1832 EFI_MAC_ADDRESS MacAddr;
1833 UINTN HwAddressSize;
1834 UINT16 VlanId;
1835 CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN];
1836 CHAR16 AttemptMacString[ISCSI_MAX_MAC_STRING_LEN];
1837 CHAR16 AttemptName[ISCSI_NAME_IFR_MAX_SIZE];
1838
1839 AttemptConfigOrder = IScsiGetVariableAndSize (
1840 L"AttemptOrder",
1841 &gIScsiConfigGuid,
1842 &AttemptConfigOrderSize
1843 );
1844 if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) {
1845 return FALSE;
1846 }
1847
1848 //
1849 // Get MAC address of this network device.
1850 //
1851 Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);
1852 if(EFI_ERROR (Status)) {
1853 return FALSE;
1854 }
1855 //
1856 // Get VLAN ID of this network device.
1857 //
1858 VlanId = NetLibGetVlanId (Controller);
1859 IScsiMacAddrToStr (&MacAddr, (UINT32) HwAddressSize, VlanId, MacString);
1860
1861 for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
1862 UnicodeSPrint (
1863 AttemptName,
1864 (UINTN) 128,
1865 L"Attempt %d",
1866 (UINTN) AttemptConfigOrder[Index]
1867 );
1868 Status = GetVariable2 (
1869 AttemptName,
1870 &gEfiIScsiInitiatorNameProtocolGuid,
1871 (VOID**)&AttemptTmp,
1872 NULL
1873 );
1874 if(AttemptTmp == NULL || EFI_ERROR (Status)) {
1875 continue;
1876 }
1877
1878 ASSERT (AttemptConfigOrder[Index] == AttemptTmp->AttemptConfigIndex);
1879
1880 if (AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED) {
1881 FreePool (AttemptTmp);
1882 continue;
1883 }
1884
1885 if (AttemptTmp->SessionConfigData.IpMode != IP_MODE_AUTOCONFIG &&
1886 AttemptTmp->SessionConfigData.IpMode != ((IpVersion == IP_VERSION_4) ? IP_MODE_IP4 : IP_MODE_IP6)) {
1887 FreePool (AttemptTmp);
1888 continue;
1889 }
1890
1891 AsciiStrToUnicodeStrS (AttemptTmp->MacString, AttemptMacString, sizeof (AttemptMacString) / sizeof (AttemptMacString[0]));
1892
1893 if (AttemptTmp->Actived == ISCSI_ACTIVE_DISABLED || StrCmp (MacString, AttemptMacString)) {
1894 continue;
1895 }
1896
1897 if(AttemptTmp->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG ||
1898 AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp == TRUE ||
1899 AttemptTmp->SessionConfigData.TargetInfoFromDhcp == TRUE) {
1900 FreePool (AttemptTmp);
1901 FreePool (AttemptConfigOrder);
1902 return TRUE;
1903 }
1904
1905 FreePool (AttemptTmp);
1906 }
1907
1908 FreePool (AttemptConfigOrder);
1909 return FALSE;
1910 }
1911
1912 /**
1913 Check whether the Controller handle is configured to use DNS protocol.
1914
1915 @param[in] Controller The handle of the controller.
1916
1917 @retval TRUE The handle of the controller need the Dns protocol.
1918 @retval FALSE The handle of the controller does not need the Dns protocol.
1919
1920 **/
1921 BOOLEAN
1922 IScsiDnsIsConfigured (
1923 IN EFI_HANDLE Controller
1924 )
1925 {
1926 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptTmp;
1927 UINT8 *AttemptConfigOrder;
1928 UINTN AttemptConfigOrderSize;
1929 UINTN Index;
1930 EFI_STATUS Status;
1931 EFI_MAC_ADDRESS MacAddr;
1932 UINTN HwAddressSize;
1933 UINT16 VlanId;
1934 CHAR16 AttemptMacString[ISCSI_MAX_MAC_STRING_LEN];
1935 CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN];
1936 CHAR16 AttemptName[ISCSI_NAME_IFR_MAX_SIZE];
1937
1938 AttemptConfigOrder = IScsiGetVariableAndSize (
1939 L"AttemptOrder",
1940 &gIScsiConfigGuid,
1941 &AttemptConfigOrderSize
1942 );
1943 if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) {
1944 return FALSE;
1945 }
1946
1947 //
1948 // Get MAC address of this network device.
1949 //
1950 Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);
1951 if(EFI_ERROR (Status)) {
1952 return FALSE;
1953 }
1954 //
1955 // Get VLAN ID of this network device.
1956 //
1957 VlanId = NetLibGetVlanId (Controller);
1958 IScsiMacAddrToStr (&MacAddr, (UINT32) HwAddressSize, VlanId, MacString);
1959
1960 for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
1961 UnicodeSPrint (
1962 AttemptName,
1963 (UINTN) 128,
1964 L"Attempt %d",
1965 (UINTN) AttemptConfigOrder[Index]
1966 );
1967
1968 Status = GetVariable2 (
1969 AttemptName,
1970 &gEfiIScsiInitiatorNameProtocolGuid,
1971 (VOID**)&AttemptTmp,
1972 NULL
1973 );
1974 if(AttemptTmp == NULL || EFI_ERROR (Status)) {
1975 continue;
1976 }
1977
1978 ASSERT (AttemptConfigOrder[Index] == AttemptTmp->AttemptConfigIndex);
1979
1980 AsciiStrToUnicodeStrS (AttemptTmp->MacString, AttemptMacString, sizeof (AttemptMacString) / sizeof (AttemptMacString[0]));
1981
1982 if (AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED || StrCmp (MacString, AttemptMacString)) {
1983 FreePool (AttemptTmp);
1984 continue;
1985 }
1986
1987 if (AttemptTmp->SessionConfigData.DnsMode || AttemptTmp->SessionConfigData.TargetInfoFromDhcp) {
1988 FreePool (AttemptTmp);
1989 FreePool (AttemptConfigOrder);
1990 return TRUE;
1991 } else {
1992 FreePool (AttemptTmp);
1993 continue;
1994 }
1995
1996 }
1997
1998 FreePool (AttemptConfigOrder);
1999 return FALSE;
2000
2001 }
2002
2003 /**
2004 Get the various configuration data.
2005
2006 @param[in] Private The iSCSI driver data.
2007
2008 @retval EFI_SUCCESS The configuration data is retrieved.
2009 @retval EFI_NOT_FOUND This iSCSI driver is not configured yet.
2010 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
2011
2012 **/
2013 EFI_STATUS
2014 IScsiGetConfigData (
2015 IN ISCSI_DRIVER_DATA *Private
2016 )
2017 {
2018 EFI_STATUS Status;
2019 CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN];
2020 CHAR16 AttemptMacString[ISCSI_MAX_MAC_STRING_LEN];
2021 UINTN Index;
2022 ISCSI_NIC_INFO *NicInfo;
2023 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
2024 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptTmp;
2025 UINT8 *AttemptConfigOrder;
2026 UINTN AttemptConfigOrderSize;
2027 CHAR16 IScsiMode[64];
2028 CHAR16 IpMode[64];
2029
2030 //
2031 // There should be at least one attempt configured.
2032 //
2033 AttemptConfigOrder = IScsiGetVariableAndSize (
2034 L"AttemptOrder",
2035 &gIScsiConfigGuid,
2036 &AttemptConfigOrderSize
2037 );
2038 if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) {
2039 return EFI_NOT_FOUND;
2040 }
2041
2042 //
2043 // Get the iSCSI Initiator Name.
2044 //
2045 mPrivate->InitiatorNameLength = ISCSI_NAME_MAX_SIZE;
2046 Status = gIScsiInitiatorName.Get (
2047 &gIScsiInitiatorName,
2048 &mPrivate->InitiatorNameLength,
2049 mPrivate->InitiatorName
2050 );
2051 if (EFI_ERROR (Status)) {
2052 return Status;
2053 }
2054
2055 //
2056 // Get the normal configuration.
2057 //
2058 for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
2059
2060 //
2061 // Check whether the attempt exists in AttemptConfig.
2062 //
2063 AttemptTmp = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]);
2064 if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED) {
2065 continue;
2066 } else if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled != ISCSI_DISABLED) {
2067 //
2068 // Check the autoconfig path to see whether it should be retried.
2069 //
2070 if (AttemptTmp->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&
2071 !AttemptTmp->AutoConfigureSuccess) {
2072 if (mPrivate->Ipv6Flag &&
2073 AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6) {
2074 //
2075 // Autoconfigure for IP6 already attempted but failed. Do not try again.
2076 //
2077 continue;
2078 } else if (!mPrivate->Ipv6Flag &&
2079 AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4) {
2080 //
2081 // Autoconfigure for IP4 already attempted but failed. Do not try again.
2082 //
2083 continue;
2084 } else {
2085 //
2086 // Try another approach for this autoconfigure path.
2087 //
2088 AttemptTmp->AutoConfigureMode =
2089 (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);
2090 AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp = TRUE;
2091 AttemptTmp->SessionConfigData.TargetInfoFromDhcp = TRUE;
2092 AttemptTmp->DhcpSuccess = FALSE;
2093
2094 //
2095 // Get some information from the dhcp server.
2096 //
2097 if (!mPrivate->Ipv6Flag) {
2098 Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);
2099 if (!EFI_ERROR (Status)) {
2100 AttemptTmp->DhcpSuccess = TRUE;
2101 }
2102 } else {
2103 Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);
2104 if (!EFI_ERROR (Status)) {
2105 AttemptTmp->DhcpSuccess = TRUE;
2106 }
2107 }
2108
2109 //
2110 // Refresh the state of this attempt to NVR.
2111 //
2112 UnicodeSPrint (
2113 mPrivate->PortString,
2114 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
2115 L"Attempt %d",
2116 (UINTN) AttemptTmp->AttemptConfigIndex
2117 );
2118
2119 gRT->SetVariable (
2120 mPrivate->PortString,
2121 &gEfiIScsiInitiatorNameProtocolGuid,
2122 ISCSI_CONFIG_VAR_ATTR,
2123 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
2124 AttemptTmp
2125 );
2126
2127 continue;
2128 }
2129 } else if (AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp &&
2130 !AttemptTmp->ValidPath &&
2131 AttemptTmp->NicIndex == mPrivate->CurrentNic) {
2132 //
2133 // If the attempt associates with the current NIC, we can
2134 // get DHCP information for already added, but failed, attempt.
2135 //
2136 AttemptTmp->DhcpSuccess = FALSE;
2137 if (!mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP4)) {
2138 Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);
2139 if (!EFI_ERROR (Status)) {
2140 AttemptTmp->DhcpSuccess = TRUE;
2141 }
2142 } else if (mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP6)) {
2143 Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);
2144 if (!EFI_ERROR (Status)) {
2145 AttemptTmp->DhcpSuccess = TRUE;
2146 }
2147 }
2148
2149 //
2150 // Refresh the state of this attempt to NVR.
2151 //
2152 UnicodeSPrint (
2153 mPrivate->PortString,
2154 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
2155 L"Attempt %d",
2156 (UINTN) AttemptTmp->AttemptConfigIndex
2157 );
2158
2159 gRT->SetVariable (
2160 mPrivate->PortString,
2161 &gEfiIScsiInitiatorNameProtocolGuid,
2162 ISCSI_CONFIG_VAR_ATTR,
2163 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
2164 AttemptTmp
2165 );
2166
2167 continue;
2168
2169 } else {
2170 continue;
2171 }
2172 }
2173
2174 //
2175 // This attempt does not exist in AttemptConfig. Try to add a new one.
2176 //
2177
2178 NicInfo = IScsiGetNicInfoByIndex (mPrivate->CurrentNic);
2179 ASSERT (NicInfo != NULL);
2180 IScsiMacAddrToStr (&NicInfo->PermanentAddress, NicInfo->HwAddressSize, NicInfo->VlanId, MacString);
2181 UnicodeSPrint (
2182 mPrivate->PortString,
2183 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
2184 L"Attempt %d",
2185 (UINTN) AttemptConfigOrder[Index]
2186 );
2187
2188 GetVariable2 (
2189 mPrivate->PortString,
2190 &gEfiIScsiInitiatorNameProtocolGuid,
2191 (VOID**)&AttemptConfigData,
2192 NULL
2193 );
2194 AsciiStrToUnicodeStrS (AttemptConfigData->MacString, AttemptMacString, sizeof (AttemptMacString) / sizeof (AttemptMacString[0]));
2195
2196 if (AttemptConfigData == NULL || AttemptConfigData->Actived == ISCSI_ACTIVE_DISABLED ||
2197 StrCmp (MacString, AttemptMacString)) {
2198 continue;
2199 }
2200
2201 ASSERT (AttemptConfigOrder[Index] == AttemptConfigData->AttemptConfigIndex);
2202
2203 AttemptConfigData->NicIndex = NicInfo->NicIndex;
2204 AttemptConfigData->DhcpSuccess = FALSE;
2205 AttemptConfigData->ValidiBFTPath = (BOOLEAN) (mPrivate->EnableMpio ? TRUE : FALSE);
2206 AttemptConfigData->ValidPath = FALSE;
2207
2208 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {
2209 AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp = TRUE;
2210 AttemptConfigData->SessionConfigData.TargetInfoFromDhcp = TRUE;
2211
2212 AttemptConfigData->AutoConfigureMode =
2213 (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);
2214 AttemptConfigData->AutoConfigureSuccess = FALSE;
2215 }
2216
2217 //
2218 // Get some information from dhcp server.
2219 //
2220 if (AttemptConfigData->SessionConfigData.Enabled != ISCSI_DISABLED &&
2221 AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp) {
2222
2223 if (!mPrivate->Ipv6Flag &&
2224 (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4 ||
2225 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4)) {
2226 Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptConfigData);
2227 if (!EFI_ERROR (Status)) {
2228 AttemptConfigData->DhcpSuccess = TRUE;
2229 }
2230 } else if (mPrivate->Ipv6Flag &&
2231 (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6 ||
2232 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6)) {
2233 Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptConfigData);
2234 if (!EFI_ERROR (Status)) {
2235 AttemptConfigData->DhcpSuccess = TRUE;
2236 }
2237 }
2238
2239 //
2240 // Refresh the state of this attempt to NVR.
2241 //
2242 UnicodeSPrint (
2243 mPrivate->PortString,
2244 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
2245 L"Attempt %d",
2246 (UINTN) AttemptConfigData->AttemptConfigIndex
2247 );
2248
2249 gRT->SetVariable (
2250 mPrivate->PortString,
2251 &gEfiIScsiInitiatorNameProtocolGuid,
2252 ISCSI_CONFIG_VAR_ATTR,
2253 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
2254 AttemptConfigData
2255 );
2256 }
2257
2258 //
2259 // Update Attempt Help Info.
2260 //
2261
2262 if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_DISABLED) {
2263 UnicodeSPrint (IScsiMode, 64, L"Disabled");
2264 } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {
2265 UnicodeSPrint (IScsiMode, 64, L"Enabled");
2266 } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
2267 UnicodeSPrint (IScsiMode, 64, L"Enabled for MPIO");
2268 }
2269
2270 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4) {
2271 UnicodeSPrint (IpMode, 64, L"IP4");
2272 } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6) {
2273 UnicodeSPrint (IpMode, 64, L"IP6");
2274 } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {
2275 UnicodeSPrint (IpMode, 64, L"Autoconfigure");
2276 }
2277
2278 UnicodeSPrint (
2279 mPrivate->PortString,
2280 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
2281 L"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s",
2282 MacString,
2283 NicInfo->BusNumber,
2284 NicInfo->DeviceNumber,
2285 NicInfo->FunctionNumber,
2286 IScsiMode,
2287 IpMode
2288 );
2289
2290 AttemptConfigData->AttemptTitleHelpToken = HiiSetString (
2291 mCallbackInfo->RegisteredHandle,
2292 0,
2293 mPrivate->PortString,
2294 NULL
2295 );
2296 if (AttemptConfigData->AttemptTitleHelpToken == 0) {
2297 return EFI_OUT_OF_RESOURCES;
2298 }
2299
2300 //
2301 // Record the attempt in global link list.
2302 //
2303 InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);
2304 mPrivate->AttemptCount++;
2305
2306 if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
2307 mPrivate->MpioCount++;
2308 mPrivate->EnableMpio = TRUE;
2309
2310 if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB) {
2311 mPrivate->Krb5MpioCount++;
2312 }
2313 } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {
2314 mPrivate->SinglePathCount++;
2315 }
2316 }
2317
2318 //
2319 // Reorder the AttemptConfig by the configured order.
2320 //
2321 for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
2322 AttemptConfigData = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]);
2323 if (AttemptConfigData == NULL) {
2324 continue;
2325 }
2326
2327 RemoveEntryList (&AttemptConfigData->Link);
2328 InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);
2329 }
2330
2331 //
2332 // Update the Main Form.
2333 //
2334 IScsiConfigUpdateAttempt ();
2335
2336 FreePool (AttemptConfigOrder);
2337
2338 //
2339 // There should be at least one attempt configuration.
2340 //
2341 if (!mPrivate->EnableMpio) {
2342 if (mPrivate->SinglePathCount == 0) {
2343 return EFI_NOT_FOUND;
2344 }
2345 mPrivate->ValidSinglePathCount = mPrivate->SinglePathCount;
2346 }
2347
2348 return EFI_SUCCESS;
2349 }
2350
2351
2352 /**
2353 Get the device path of the iSCSI tcp connection and update it.
2354
2355 @param Session The iSCSI session.
2356
2357 @return The updated device path.
2358 @retval NULL Other errors as indicated.
2359
2360 **/
2361 EFI_DEVICE_PATH_PROTOCOL *
2362 IScsiGetTcpConnDevicePath (
2363 IN ISCSI_SESSION *Session
2364 )
2365 {
2366 ISCSI_CONNECTION *Conn;
2367 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2368 EFI_STATUS Status;
2369 EFI_DEV_PATH *DPathNode;
2370 UINTN PathLen;
2371
2372 if (Session->State != SESSION_STATE_LOGGED_IN) {
2373 return NULL;
2374 }
2375
2376 Conn = NET_LIST_USER_STRUCT_S (
2377 Session->Conns.ForwardLink,
2378 ISCSI_CONNECTION,
2379 Link,
2380 ISCSI_CONNECTION_SIGNATURE
2381 );
2382
2383 Status = gBS->HandleProtocol (
2384 Conn->TcpIo.Handle,
2385 &gEfiDevicePathProtocolGuid,
2386 (VOID **) &DevicePath
2387 );
2388 if (EFI_ERROR (Status)) {
2389 return NULL;
2390 }
2391 //
2392 // Duplicate it.
2393 //
2394 DevicePath = DuplicateDevicePath (DevicePath);
2395 if (DevicePath == NULL) {
2396 return NULL;
2397 }
2398
2399 DPathNode = (EFI_DEV_PATH *) DevicePath;
2400
2401 while (!IsDevicePathEnd (&DPathNode->DevPath)) {
2402 if (DevicePathType (&DPathNode->DevPath) == MESSAGING_DEVICE_PATH) {
2403 if (!Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv4_DP) {
2404 DPathNode->Ipv4.LocalPort = 0;
2405
2406 DPathNode->Ipv4.StaticIpAddress =
2407 (BOOLEAN) (!Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp);
2408
2409 //
2410 // Add a judgement here to support previous versions of IPv4_DEVICE_PATH.
2411 // In previous versions of IPv4_DEVICE_PATH, GatewayIpAddress and SubnetMask
2412 // do not exist.
2413 // In new version of IPv4_DEVICE_PATH, structcure length is 27.
2414 //
2415
2416 PathLen = DevicePathNodeLength (&DPathNode->Ipv4);
2417
2418 if (PathLen == IP4_NODE_LEN_NEW_VERSIONS) {
2419
2420 IP4_COPY_ADDRESS (
2421 &DPathNode->Ipv4.GatewayIpAddress,
2422 &Session->ConfigData->SessionConfigData.Gateway
2423 );
2424
2425 IP4_COPY_ADDRESS (
2426 &DPathNode->Ipv4.SubnetMask,
2427 &Session->ConfigData->SessionConfigData.SubnetMask
2428 );
2429 }
2430
2431 break;
2432 } else if (Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv6_DP) {
2433 DPathNode->Ipv6.LocalPort = 0;
2434
2435 //
2436 // Add a judgement here to support previous versions of IPv6_DEVICE_PATH.
2437 // In previous versions of IPv6_DEVICE_PATH, IpAddressOrigin, PrefixLength
2438 // and GatewayIpAddress do not exist.
2439 // In new version of IPv6_DEVICE_PATH, structure length is 60, while in
2440 // old versions, the length is 43.
2441 //
2442
2443 PathLen = DevicePathNodeLength (&DPathNode->Ipv6);
2444
2445 if (PathLen == IP6_NODE_LEN_NEW_VERSIONS ) {
2446
2447 DPathNode->Ipv6.IpAddressOrigin = 0;
2448 DPathNode->Ipv6.PrefixLength = IP6_PREFIX_LENGTH;
2449 ZeroMem (&DPathNode->Ipv6.GatewayIpAddress, sizeof (EFI_IPv6_ADDRESS));
2450 }
2451 else if (PathLen == IP6_NODE_LEN_OLD_VERSIONS) {
2452
2453 //
2454 // StaticIPAddress is a field in old versions of IPv6_DEVICE_PATH, while ignored in new
2455 // version. Set StaticIPAddress through its' offset in old IPv6_DEVICE_PATH.
2456 //
2457 *((UINT8 *)(&DPathNode->Ipv6) + IP6_OLD_IPADDRESS_OFFSET) =
2458 (BOOLEAN) (!Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp);
2459 }
2460
2461 break;
2462 }
2463 }
2464
2465 DPathNode = (EFI_DEV_PATH *) NextDevicePathNode (&DPathNode->DevPath);
2466 }
2467
2468 return DevicePath;
2469 }
2470
2471
2472 /**
2473 Abort the session when the transition from BS to RT is initiated.
2474
2475 @param[in] Event The event signaled.
2476 @param[in] Context The iSCSI driver data.
2477
2478 **/
2479 VOID
2480 EFIAPI
2481 IScsiOnExitBootService (
2482 IN EFI_EVENT Event,
2483 IN VOID *Context
2484 )
2485 {
2486 ISCSI_DRIVER_DATA *Private;
2487
2488 Private = (ISCSI_DRIVER_DATA *) Context;
2489
2490 gBS->CloseEvent (Private->ExitBootServiceEvent);
2491 Private->ExitBootServiceEvent = NULL;
2492
2493 if (Private->Session != NULL) {
2494 IScsiSessionAbort (Private->Session);
2495 }
2496 }
2497
2498 /**
2499 Tests whether a controller handle is being managed by IScsi driver.
2500
2501 This function tests whether the driver specified by DriverBindingHandle is
2502 currently managing the controller specified by ControllerHandle. This test
2503 is performed by evaluating if the the protocol specified by ProtocolGuid is
2504 present on ControllerHandle and is was opened by DriverBindingHandle and Nic
2505 Device handle with an attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
2506 If ProtocolGuid is NULL, then ASSERT().
2507
2508 @param ControllerHandle A handle for a controller to test.
2509 @param DriverBindingHandle Specifies the driver binding handle for the
2510 driver.
2511 @param ProtocolGuid Specifies the protocol that the driver specified
2512 by DriverBindingHandle opens in its Start()
2513 function.
2514
2515 @retval EFI_SUCCESS ControllerHandle is managed by the driver
2516 specified by DriverBindingHandle.
2517 @retval EFI_UNSUPPORTED ControllerHandle is not managed by the driver
2518 specified by DriverBindingHandle.
2519
2520 **/
2521 EFI_STATUS
2522 EFIAPI
2523 IScsiTestManagedDevice (
2524 IN EFI_HANDLE ControllerHandle,
2525 IN EFI_HANDLE DriverBindingHandle,
2526 IN EFI_GUID *ProtocolGuid
2527 )
2528 {
2529 EFI_STATUS Status;
2530 VOID *ManagedInterface;
2531 EFI_HANDLE NicControllerHandle;
2532
2533 ASSERT (ProtocolGuid != NULL);
2534
2535 NicControllerHandle = NetLibGetNicHandle (ControllerHandle, ProtocolGuid);
2536 if (NicControllerHandle == NULL) {
2537 return EFI_UNSUPPORTED;
2538 }
2539
2540 Status = gBS->OpenProtocol (
2541 ControllerHandle,
2542 (EFI_GUID *) ProtocolGuid,
2543 &ManagedInterface,
2544 DriverBindingHandle,
2545 NicControllerHandle,
2546 EFI_OPEN_PROTOCOL_BY_DRIVER
2547 );
2548 if (!EFI_ERROR (Status)) {
2549 gBS->CloseProtocol (
2550 ControllerHandle,
2551 (EFI_GUID *) ProtocolGuid,
2552 DriverBindingHandle,
2553 NicControllerHandle
2554 );
2555 return EFI_UNSUPPORTED;
2556 }
2557
2558 if (Status != EFI_ALREADY_STARTED) {
2559 return EFI_UNSUPPORTED;
2560 }
2561
2562 return EFI_SUCCESS;
2563 }