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