Fix a bug about the iSCSI DHCP dependency issue.
[mirror_edk2.git] / NetworkPkg / IScsiDxe / IScsiMisc.c
1 /** @file\r
2   Miscellaneous routines for iSCSI driver.\r
3 \r
4 Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution.  The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9 \r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12 \r
13 **/\r
14 \r
15 #include "IScsiImpl.h"\r
16 \r
17 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8  IScsiHexString[] = "0123456789ABCDEFabcdef";\r
18 \r
19 /**\r
20   Removes (trims) specified leading and trailing characters from a string.\r
21 \r
22   @param[in, out] Str   Pointer to the null-terminated string to be trimmed.\r
23                         On return, Str will hold the trimmed string. \r
24 \r
25   @param[in]      CharC Character will be trimmed from str.\r
26 \r
27 **/\r
28 VOID\r
29 IScsiStrTrim (\r
30   IN OUT CHAR16   *Str,\r
31   IN     CHAR16   CharC\r
32   )\r
33 {\r
34   CHAR16  *Pointer1;\r
35   CHAR16  *Pointer2;\r
36   \r
37   if (*Str == 0) {\r
38     return ;\r
39   }\r
40   \r
41   //\r
42   // Trim off the leading and trailing characters c\r
43   //\r
44   for (Pointer1 = Str; (*Pointer1 != 0) && (*Pointer1 == CharC); Pointer1++) {\r
45     ;\r
46   }\r
47   \r
48   Pointer2 = Str;\r
49   if (Pointer2 == Pointer1) {\r
50     while (*Pointer1 != 0) {\r
51       Pointer2++;\r
52       Pointer1++;\r
53     }\r
54   } else {\r
55     while (*Pointer1 != 0) {    \r
56     *Pointer2 = *Pointer1;    \r
57     Pointer1++;\r
58     Pointer2++;\r
59     }\r
60     *Pointer2 = 0;\r
61   }\r
62   \r
63   \r
64   for (Pointer1 = Str + StrLen(Str) - 1; Pointer1 >= Str && *Pointer1 == CharC; Pointer1--) {\r
65     ;\r
66   }\r
67   if  (Pointer1 !=  Str + StrLen(Str) - 1) { \r
68     *(Pointer1 + 1) = 0;\r
69   }\r
70 }\r
71 \r
72 /**\r
73   Calculate the prefix length of the IPv4 subnet mask.\r
74 \r
75   @param[in]  SubnetMask The IPv4 subnet mask.\r
76 \r
77   @return     The prefix length of the subnet mask.\r
78   @retval 0   Other errors as indicated.\r
79 \r
80 **/\r
81 UINT8\r
82 IScsiGetSubnetMaskPrefixLength (\r
83   IN EFI_IPv4_ADDRESS  *SubnetMask\r
84   )\r
85 {\r
86   UINT8   Len;\r
87   UINT32  ReverseMask;\r
88 \r
89   //\r
90   // The SubnetMask is in network byte order.\r
91   //\r
92   ReverseMask = (SubnetMask->Addr[0] << 24) | (SubnetMask->Addr[1] << 16) | (SubnetMask->Addr[2] << 8) | (SubnetMask->Addr[3]);\r
93 \r
94   //\r
95   // Reverse it.\r
96   //\r
97   ReverseMask = ~ReverseMask;\r
98 \r
99   if ((ReverseMask & (ReverseMask + 1)) != 0) {\r
100     return 0;\r
101   }\r
102 \r
103   Len = 0;\r
104 \r
105   while (ReverseMask != 0) {\r
106     ReverseMask = ReverseMask >> 1;\r
107     Len++;\r
108   }\r
109 \r
110   return (UINT8) (32 - Len);\r
111 }\r
112 \r
113 \r
114 /**\r
115   Convert the hexadecimal encoded LUN string into the 64-bit LUN.\r
116 \r
117   @param[in]   Str             The hexadecimal encoded LUN string.\r
118   @param[out]  Lun             Storage to return the 64-bit LUN.\r
119 \r
120   @retval EFI_SUCCESS            The 64-bit LUN is stored in Lun.\r
121   @retval EFI_INVALID_PARAMETER  The string is malformatted.\r
122 \r
123 **/\r
124 EFI_STATUS\r
125 IScsiAsciiStrToLun (\r
126   IN  CHAR8  *Str,\r
127   OUT UINT8  *Lun\r
128   )\r
129 {\r
130   UINTN   Index, IndexValue, IndexNum, SizeStr;\r
131   CHAR8   TemStr[2];\r
132   UINT8   TemValue;\r
133   UINT16  Value[4];\r
134   \r
135   ZeroMem (Lun, 8);\r
136   ZeroMem (TemStr, 2);\r
137   ZeroMem ((UINT8 *) Value, sizeof (Value));\r
138   SizeStr    = AsciiStrLen (Str);  \r
139   IndexValue = 0;\r
140   IndexNum   = 0;\r
141 \r
142   for (Index = 0; Index < SizeStr; Index ++) {\r
143     TemStr[0] = Str[Index];\r
144     TemValue = (UINT8) AsciiStrHexToUint64 (TemStr);\r
145     if (TemValue == 0 && TemStr[0] != '0') {\r
146       if ((TemStr[0] != '-') || (IndexNum == 0)) {\r
147         //\r
148         // Invalid Lun Char.\r
149         //\r
150         return EFI_INVALID_PARAMETER;\r
151       }\r
152     }\r
153     \r
154     if ((TemValue == 0) && (TemStr[0] == '-')) {\r
155       //\r
156       // Next Lun value.\r
157       //\r
158       if (++IndexValue >= 4) {\r
159         //\r
160         // Max 4 Lun value.\r
161         //\r
162         return EFI_INVALID_PARAMETER;\r
163       }\r
164       //\r
165       // Restart str index for the next lun value.\r
166       //\r
167       IndexNum = 0;\r
168       continue;\r
169     }\r
170     \r
171     if (++IndexNum > 4) {\r
172       //     \r
173       // Each Lun Str can't exceed size 4, because it will be as UINT16 value.\r
174       //\r
175       return EFI_INVALID_PARAMETER;\r
176     }\r
177     \r
178     //\r
179     // Combine UINT16 value.\r
180     //\r
181     Value[IndexValue] = (UINT16) ((Value[IndexValue] << 4) + TemValue);\r
182   }\r
183  \r
184   for (Index = 0; Index <= IndexValue; Index ++) {\r
185     *((UINT16 *) &Lun[Index * 2]) =  HTONS (Value[Index]);\r
186   }\r
187   \r
188   return EFI_SUCCESS;\r
189 }\r
190 \r
191 /**\r
192   Convert the 64-bit LUN into the hexadecimal encoded LUN string.\r
193 \r
194   @param[in]   Lun The 64-bit LUN.\r
195   @param[out]  Str The storage to return the hexadecimal encoded LUN string.\r
196 \r
197 **/\r
198 VOID\r
199 IScsiLunToUnicodeStr (\r
200   IN UINT8    *Lun,\r
201   OUT CHAR16  *Str\r
202   )\r
203 {\r
204   UINTN   Index;\r
205   CHAR16  *TempStr;\r
206 \r
207   TempStr = Str;\r
208 \r
209   for (Index = 0; Index < 4; Index++) {\r
210 \r
211     if ((Lun[2 * Index] | Lun[2 * Index + 1]) == 0) {\r
212       StrCpy (TempStr, L"0-");\r
213     } else {\r
214       TempStr[0]  = (CHAR16) IScsiHexString[Lun[2 * Index] >> 4];\r
215       TempStr[1]  = (CHAR16) IScsiHexString[Lun[2 * Index] & 0x0F];\r
216       TempStr[2]  = (CHAR16) IScsiHexString[Lun[2 * Index + 1] >> 4];\r
217       TempStr[3]  = (CHAR16) IScsiHexString[Lun[2 * Index + 1] & 0x0F];\r
218       TempStr[4]  = L'-';\r
219       TempStr[5]  = 0;\r
220 \r
221       IScsiStrTrim (TempStr, L'0');\r
222     }\r
223 \r
224     TempStr += StrLen (TempStr);\r
225   }\r
226 \r
227   Str[StrLen (Str) - 1] = 0;\r
228 \r
229   for (Index = StrLen (Str) - 1; Index > 1; Index = Index - 2) {\r
230     if ((Str[Index] == L'0') && (Str[Index - 1] == L'-')) {\r
231       Str[Index - 1] = 0;\r
232     } else {\r
233       break;\r
234     }\r
235   }\r
236 }\r
237 \r
238 /**\r
239   Convert the formatted IP address into the binary IP address.\r
240 \r
241   @param[in]   Str               The UNICODE string.\r
242   @param[in]   IpMode            Indicates whether the IP address is v4 or v6.\r
243   @param[out]  Ip                The storage to return the ASCII string.\r
244 \r
245   @retval EFI_SUCCESS            The binary IP address is returned in Ip.\r
246   @retval EFI_INVALID_PARAMETER  The IP string is malformatted or IpMode is\r
247                                  invalid.\r
248 \r
249 **/\r
250 EFI_STATUS\r
251 IScsiAsciiStrToIp (\r
252   IN  CHAR8             *Str,\r
253   IN  UINT8             IpMode,\r
254   OUT EFI_IP_ADDRESS    *Ip\r
255   )\r
256 {\r
257   EFI_STATUS            Status;\r
258 \r
259   if (IpMode == IP_MODE_IP4 || IpMode == IP_MODE_AUTOCONFIG_IP4) {\r
260     return NetLibAsciiStrToIp4 (Str, &Ip->v4);\r
261 \r
262   } else if (IpMode == IP_MODE_IP6 || IpMode == IP_MODE_AUTOCONFIG_IP6) {\r
263     return NetLibAsciiStrToIp6 (Str, &Ip->v6);\r
264 \r
265   } else if (IpMode == IP_MODE_AUTOCONFIG) {\r
266     Status = NetLibAsciiStrToIp4 (Str, &Ip->v4);\r
267     if (!EFI_ERROR (Status)) {\r
268       return Status;\r
269     }\r
270     return NetLibAsciiStrToIp6 (Str, &Ip->v6);\r
271 \r
272   }\r
273 \r
274   return EFI_INVALID_PARAMETER;\r
275 }\r
276 \r
277 /**\r
278   Convert the mac address into a hexadecimal encoded "-" seperated string.\r
279 \r
280   @param[in]  Mac     The mac address.\r
281   @param[in]  Len     Length in bytes of the mac address.\r
282   @param[in]  VlanId  VLAN ID of the network device.\r
283   @param[out] Str     The storage to return the mac string.\r
284 \r
285 **/\r
286 VOID\r
287 IScsiMacAddrToStr (\r
288   IN  EFI_MAC_ADDRESS  *Mac,\r
289   IN  UINT32           Len,\r
290   IN  UINT16           VlanId,\r
291   OUT CHAR16           *Str\r
292   )\r
293 {\r
294   UINT32  Index;\r
295   CHAR16  *String;\r
296 \r
297   for (Index = 0; Index < Len; Index++) {\r
298     Str[3 * Index]      = (CHAR16) IScsiHexString[(Mac->Addr[Index] >> 4) & 0x0F];\r
299     Str[3 * Index + 1]  = (CHAR16) IScsiHexString[Mac->Addr[Index] & 0x0F];\r
300     Str[3 * Index + 2]  = L':';\r
301   }\r
302 \r
303   String = &Str[3 * Index - 1] ;\r
304   if (VlanId != 0) {\r
305     String += UnicodeSPrint (String, 6 * sizeof (CHAR16), L"\\%04x", (UINTN) VlanId);\r
306   }\r
307 \r
308   *String = L'\0';\r
309 }\r
310 \r
311 /**\r
312   Convert the binary encoded buffer into a hexadecimal encoded string.\r
313 \r
314   @param[in]       BinBuffer   The buffer containing the binary data.\r
315   @param[in]       BinLength   Length of the binary buffer.\r
316   @param[in, out]  HexStr      Pointer to the string.\r
317   @param[in, out]  HexLength   The length of the string.\r
318 \r
319   @retval EFI_SUCCESS          The binary data is converted to the hexadecimal string \r
320                                and the length of the string is updated.\r
321   @retval EFI_BUFFER_TOO_SMALL The string is too small.\r
322   @retval EFI_INVALID_PARAMETER The IP string is malformatted.\r
323 \r
324 **/\r
325 EFI_STATUS\r
326 IScsiBinToHex (\r
327   IN     UINT8  *BinBuffer,\r
328   IN     UINT32 BinLength,\r
329   IN OUT CHAR8  *HexStr,\r
330   IN OUT UINT32 *HexLength\r
331   )\r
332 {\r
333   UINTN Index;\r
334 \r
335   if ((HexStr == NULL) || (BinBuffer == NULL) || (BinLength == 0)) {\r
336     return EFI_INVALID_PARAMETER;\r
337   }\r
338 \r
339   if (((*HexLength) - 3) < BinLength * 2) {\r
340     *HexLength = BinLength * 2 + 3;\r
341     return EFI_BUFFER_TOO_SMALL;\r
342   }\r
343 \r
344   *HexLength = BinLength * 2 + 3;\r
345   //\r
346   // Prefix for Hex String.\r
347   //\r
348   HexStr[0] = '0';\r
349   HexStr[1] = 'x';\r
350 \r
351   for (Index = 0; Index < BinLength; Index++) {\r
352     HexStr[Index * 2 + 2] = IScsiHexString[BinBuffer[Index] >> 4];\r
353     HexStr[Index * 2 + 3] = IScsiHexString[BinBuffer[Index] & 0xf];\r
354   }\r
355 \r
356   HexStr[Index * 2 + 2] = '\0';\r
357 \r
358   return EFI_SUCCESS;\r
359 }\r
360 \r
361 \r
362 /**\r
363   Convert the hexadecimal string into a binary encoded buffer.\r
364 \r
365   @param[in, out]  BinBuffer   The binary buffer.\r
366   @param[in, out]  BinLength   Length of the binary buffer.\r
367   @param[in]       HexStr      The hexadecimal string.\r
368 \r
369   @retval EFI_SUCCESS          The hexadecimal string is converted into a binary\r
370                                encoded buffer.\r
371   @retval EFI_BUFFER_TOO_SMALL The binary buffer is too small to hold the converted data.\r
372 \r
373 **/\r
374 EFI_STATUS\r
375 IScsiHexToBin (\r
376   IN OUT UINT8  *BinBuffer,\r
377   IN OUT UINT32 *BinLength,\r
378   IN     CHAR8  *HexStr\r
379   )\r
380 {\r
381   UINTN   Index;\r
382   UINTN   Length;\r
383   UINT8   Digit;\r
384   CHAR8   TemStr[2];\r
385   \r
386   ZeroMem (TemStr, sizeof (TemStr));\r
387 \r
388   //\r
389   // Find out how many hex characters the string has.\r
390   //\r
391   if ((HexStr[0] == '0') && ((HexStr[1] == 'x') || (HexStr[1] == 'X'))) {\r
392     HexStr += 2;\r
393   }\r
394   \r
395   Length = AsciiStrLen (HexStr);\r
396 \r
397   for (Index = 0; Index < Length; Index ++) {\r
398     TemStr[0] = HexStr[Index];\r
399     Digit = (UINT8) AsciiStrHexToUint64 (TemStr);\r
400     if (Digit == 0 && TemStr[0] != '0') {\r
401       //\r
402       // Invalid Lun Char.\r
403       //\r
404       break;\r
405     }\r
406     if ((Index & 1) == 0) {\r
407       BinBuffer [Index/2] = Digit;\r
408     } else {\r
409       BinBuffer [Index/2] = (UINT8) ((BinBuffer [Index/2] << 4) + Digit);\r
410     }\r
411   }\r
412   \r
413   *BinLength = (UINT32) ((Index + 1)/2);\r
414 \r
415   return EFI_SUCCESS;\r
416 }\r
417 \r
418 \r
419 /**\r
420   Convert the decimal-constant string or hex-constant string into a numerical value.\r
421 \r
422   @param[in] Str                    String in decimal or hex.\r
423 \r
424   @return The numerical value.\r
425 \r
426 **/\r
427 UINTN\r
428 IScsiNetNtoi (\r
429   IN     CHAR8  *Str\r
430   )\r
431 {\r
432   if ((Str[0] == '0') && ((Str[1] == 'x') || (Str[1] == 'X'))) {\r
433     Str += 2;\r
434 \r
435     return AsciiStrHexToUintn (Str);\r
436   }\r
437 \r
438   return AsciiStrDecimalToUintn (Str);\r
439 }\r
440 \r
441 \r
442 /**\r
443   Generate random numbers.\r
444 \r
445   @param[in, out]  Rand       The buffer to contain random numbers.\r
446   @param[in]       RandLength The length of the Rand buffer.\r
447 \r
448 **/\r
449 VOID\r
450 IScsiGenRandom (\r
451   IN OUT UINT8  *Rand,\r
452   IN     UINTN  RandLength\r
453   )\r
454 {\r
455   UINT32  Random;\r
456 \r
457   while (RandLength > 0) {\r
458     Random  = NET_RANDOM (NetRandomInitSeed ());\r
459     *Rand++ = (UINT8) (Random);\r
460     RandLength--;\r
461   }\r
462 }\r
463 \r
464 \r
465 /**\r
466   Record the NIC info in global structure.\r
467 \r
468   @param[in]  Controller         The handle of the controller.\r
469 \r
470   @retval EFI_SUCCESS            The operation is completed.\r
471   @retval EFI_OUT_OF_RESOURCES   Do not have sufficient resources to finish this\r
472                                  operation.\r
473 \r
474 **/\r
475 EFI_STATUS\r
476 IScsiAddNic (\r
477   IN EFI_HANDLE  Controller\r
478   )\r
479 {\r
480   EFI_STATUS                  Status;\r
481   ISCSI_NIC_INFO              *NicInfo;\r
482   LIST_ENTRY                  *Entry;\r
483   EFI_MAC_ADDRESS             MacAddr;\r
484   UINTN                       HwAddressSize;\r
485   UINT16                      VlanId;\r
486 \r
487   //\r
488   // Get MAC address of this network device.\r
489   //\r
490   Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);\r
491   if (EFI_ERROR (Status)) {\r
492     return Status;\r
493   }\r
494 \r
495   //\r
496   // Get VLAN ID of this network device.\r
497   //\r
498   VlanId = NetLibGetVlanId (Controller);\r
499 \r
500   //\r
501   // Check whether the NIC info already exists. Return directly if so.\r
502   //\r
503   NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {\r
504     NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);\r
505     if (NicInfo->HwAddressSize == HwAddressSize &&\r
506         CompareMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize) == 0 &&\r
507         NicInfo->VlanId == VlanId) {\r
508       mPrivate->CurrentNic = NicInfo->NicIndex;\r
509       return EFI_SUCCESS;\r
510     }\r
511 \r
512     if (mPrivate->MaxNic < NicInfo->NicIndex) {\r
513       mPrivate->MaxNic = NicInfo->NicIndex;\r
514     }\r
515   }\r
516 \r
517   //\r
518   // Record the NIC info in private structure.\r
519   //\r
520   NicInfo = AllocateZeroPool (sizeof (ISCSI_NIC_INFO));\r
521   if (NicInfo == NULL) {\r
522     return EFI_OUT_OF_RESOURCES;\r
523   }\r
524 \r
525   CopyMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize);\r
526   NicInfo->HwAddressSize  = (UINT32) HwAddressSize;\r
527   NicInfo->VlanId         = VlanId;\r
528   NicInfo->NicIndex       = (UINT8) (mPrivate->MaxNic + 1);\r
529   mPrivate->MaxNic        = NicInfo->NicIndex;\r
530 \r
531   //\r
532   // Get the PCI location.\r
533   //\r
534   IScsiGetNICPciLocation (\r
535     Controller,\r
536     &NicInfo->BusNumber,\r
537     &NicInfo->DeviceNumber,\r
538     &NicInfo->FunctionNumber\r
539     );\r
540 \r
541   InsertTailList (&mPrivate->NicInfoList, &NicInfo->Link);\r
542   mPrivate->NicCount++;\r
543 \r
544   mPrivate->CurrentNic = NicInfo->NicIndex;\r
545   return EFI_SUCCESS;\r
546 }\r
547 \r
548 \r
549 /**\r
550   Delete the recorded NIC info from global structure. Also delete corresponding\r
551   attempts.\r
552 \r
553   @param[in]  Controller         The handle of the controller.\r
554 \r
555   @retval EFI_SUCCESS            The operation is completed.\r
556   @retval EFI_NOT_FOUND          The NIC info to be deleted is not recorded.\r
557 \r
558 **/\r
559 EFI_STATUS\r
560 IScsiRemoveNic (\r
561   IN EFI_HANDLE  Controller\r
562   )\r
563 {\r
564   EFI_STATUS                  Status;\r
565   ISCSI_NIC_INFO              *NicInfo;\r
566   LIST_ENTRY                  *Entry;\r
567   LIST_ENTRY                  *NextEntry;\r
568   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;\r
569   ISCSI_NIC_INFO              *ThisNic;\r
570   EFI_MAC_ADDRESS             MacAddr;\r
571   UINTN                       HwAddressSize;\r
572   UINT16                      VlanId;\r
573 \r
574   //\r
575   // Get MAC address of this network device.\r
576   //\r
577   Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);\r
578   if (EFI_ERROR (Status)) {\r
579     return Status;\r
580   }\r
581 \r
582   //\r
583   // Get VLAN ID of this network device.\r
584   //\r
585   VlanId = NetLibGetVlanId (Controller);\r
586 \r
587   //\r
588   // Check whether the NIC information exists.\r
589   //\r
590   ThisNic = NULL;\r
591 \r
592   NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {\r
593     NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);\r
594     if (NicInfo->HwAddressSize == HwAddressSize &&\r
595         CompareMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize) == 0 &&\r
596         NicInfo->VlanId == VlanId) {\r
597 \r
598       ThisNic = NicInfo;\r
599       break;\r
600     }\r
601   }\r
602 \r
603   if (ThisNic == NULL) {\r
604     return EFI_NOT_FOUND;\r
605   }\r
606 \r
607   mPrivate->CurrentNic = ThisNic->NicIndex;\r
608 \r
609   RemoveEntryList (&ThisNic->Link);\r
610   FreePool (ThisNic);\r
611   mPrivate->NicCount--;\r
612 \r
613   //\r
614   // Remove all attempts related to this NIC.\r
615   //\r
616   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mPrivate->AttemptConfigs) {\r
617     AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);\r
618     if (AttemptConfigData->NicIndex == mPrivate->CurrentNic) {\r
619       RemoveEntryList (&AttemptConfigData->Link);\r
620       mPrivate->AttemptCount--;\r
621 \r
622       if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO && mPrivate->MpioCount > 0) {\r
623         if (--mPrivate->MpioCount == 0) {\r
624           mPrivate->EnableMpio = FALSE;\r
625         }\r
626 \r
627         if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB && mPrivate->Krb5MpioCount > 0) {\r
628           mPrivate->Krb5MpioCount--;\r
629         }\r
630 \r
631       } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED && mPrivate->SinglePathCount > 0) {\r
632         mPrivate->SinglePathCount--;\r
633 \r
634         if (mPrivate->ValidSinglePathCount > 0) {\r
635           mPrivate->ValidSinglePathCount--;\r
636         }\r
637       }\r
638 \r
639       FreePool (AttemptConfigData);\r
640     }\r
641   }\r
642 \r
643   //\r
644   // Free attempt is created but not saved to system.\r
645   //\r
646   if (mPrivate->NewAttempt != NULL) {\r
647     FreePool (mPrivate->NewAttempt);\r
648     mPrivate->NewAttempt = NULL;\r
649   }\r
650 \r
651   return EFI_SUCCESS;\r
652 }\r
653 \r
654 \r
655 /**\r
656   Get the recorded NIC info from global structure by the Index.\r
657 \r
658   @param[in]  NicIndex          The index indicates the position of NIC info.\r
659 \r
660   @return Pointer to the NIC info, or NULL if not found.\r
661 \r
662 **/\r
663 ISCSI_NIC_INFO *\r
664 IScsiGetNicInfoByIndex (\r
665   IN UINT8      NicIndex\r
666   )\r
667 {\r
668   LIST_ENTRY        *Entry;\r
669   ISCSI_NIC_INFO    *NicInfo;\r
670 \r
671   NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {\r
672     NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);\r
673     if (NicInfo->NicIndex == NicIndex) {\r
674       return NicInfo;\r
675     }\r
676   }\r
677 \r
678   return NULL;\r
679 }\r
680 \r
681 \r
682 /**\r
683   Get the NIC's PCI location and return it accroding to the composited\r
684   format defined in iSCSI Boot Firmware Table.\r
685 \r
686   @param[in]   Controller        The handle of the controller.\r
687   @param[out]  Bus               The bus number.\r
688   @param[out]  Device            The device number.\r
689   @param[out]  Function          The function number.\r
690 \r
691   @return      The composited representation of the NIC PCI location.\r
692 \r
693 **/\r
694 UINT16\r
695 IScsiGetNICPciLocation (\r
696   IN EFI_HANDLE  Controller,\r
697   OUT UINTN      *Bus,\r
698   OUT UINTN      *Device,\r
699   OUT UINTN      *Function\r
700   )\r
701 {\r
702   EFI_STATUS                Status;\r
703   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
704   EFI_HANDLE                PciIoHandle;\r
705   EFI_PCI_IO_PROTOCOL       *PciIo;\r
706   UINTN                     Segment;\r
707 \r
708   Status = gBS->HandleProtocol (\r
709                   Controller,\r
710                   &gEfiDevicePathProtocolGuid,\r
711                   (VOID **) &DevicePath\r
712                   );\r
713   if (EFI_ERROR (Status)) {\r
714     return 0;\r
715   }\r
716 \r
717   Status = gBS->LocateDevicePath (\r
718                   &gEfiPciIoProtocolGuid,\r
719                   &DevicePath,\r
720                   &PciIoHandle\r
721                   );\r
722   if (EFI_ERROR (Status)) {\r
723     return 0;\r
724   }\r
725 \r
726   Status = gBS->HandleProtocol (PciIoHandle, &gEfiPciIoProtocolGuid, (VOID **) &PciIo);\r
727   if (EFI_ERROR (Status)) {\r
728     return 0;\r
729   }\r
730 \r
731   Status = PciIo->GetLocation (PciIo, &Segment, Bus, Device, Function);\r
732   if (EFI_ERROR (Status)) {\r
733     return 0;\r
734   }\r
735 \r
736   return (UINT16) ((*Bus << 8) | (*Device << 3) | *Function);\r
737 }\r
738 \r
739 \r
740 /**\r
741   Read the EFI variable (VendorGuid/Name) and return a dynamically allocated\r
742   buffer, and the size of the buffer. If failure, return NULL.\r
743 \r
744   @param[in]   Name                   String part of EFI variable name.\r
745   @param[in]   VendorGuid             GUID part of EFI variable name.\r
746   @param[out]  VariableSize           Returns the size of the EFI variable that was read.\r
747 \r
748   @return Dynamically allocated memory that contains a copy of the EFI variable.\r
749   @return Caller is responsible freeing the buffer.\r
750   @retval NULL                   Variable was not read.\r
751 \r
752 **/\r
753 VOID *\r
754 IScsiGetVariableAndSize (\r
755   IN  CHAR16              *Name,\r
756   IN  EFI_GUID            *VendorGuid,\r
757   OUT UINTN               *VariableSize\r
758   )\r
759 {\r
760   EFI_STATUS  Status;\r
761   UINTN       BufferSize;\r
762   VOID        *Buffer;\r
763 \r
764   Buffer = NULL;\r
765 \r
766   //\r
767   // Pass in a zero size buffer to find the required buffer size.\r
768   //\r
769   BufferSize  = 0;\r
770   Status      = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);\r
771   if (Status == EFI_BUFFER_TOO_SMALL) {\r
772     //\r
773     // Allocate the buffer to return\r
774     //\r
775     Buffer = AllocateZeroPool (BufferSize);\r
776     if (Buffer == NULL) {\r
777       return NULL;\r
778     }\r
779     //\r
780     // Read variable into the allocated buffer.\r
781     //\r
782     Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);\r
783     if (EFI_ERROR (Status)) {\r
784       BufferSize = 0;\r
785     }\r
786   }\r
787 \r
788   *VariableSize = BufferSize;\r
789   return Buffer;\r
790 }\r
791 \r
792 \r
793 /**\r
794   Create the iSCSI driver data.\r
795 \r
796   @param[in] Image      The handle of the driver image.\r
797   @param[in] Controller The handle of the controller.\r
798 \r
799   @return The iSCSI driver data created.\r
800   @retval NULL Other errors as indicated.\r
801 \r
802 **/\r
803 ISCSI_DRIVER_DATA *\r
804 IScsiCreateDriverData (\r
805   IN EFI_HANDLE  Image,\r
806   IN EFI_HANDLE  Controller\r
807   )\r
808 {\r
809   ISCSI_DRIVER_DATA *Private;\r
810   EFI_STATUS        Status;\r
811 \r
812   Private = AllocateZeroPool (sizeof (ISCSI_DRIVER_DATA));\r
813   if (Private == NULL) {\r
814     return NULL;\r
815   }\r
816 \r
817   Private->Signature  = ISCSI_DRIVER_DATA_SIGNATURE;\r
818   Private->Image      = Image;\r
819   Private->Controller = Controller;\r
820   Private->Session    = NULL;\r
821 \r
822   //\r
823   // Create an event to be signaled when the BS to RT transition is triggerd so\r
824   // as to abort the iSCSI session.\r
825   //\r
826   Status = gBS->CreateEventEx (\r
827                   EVT_NOTIFY_SIGNAL,\r
828                   TPL_CALLBACK,\r
829                   IScsiOnExitBootService,\r
830                   Private,\r
831                   &gEfiEventExitBootServicesGuid,\r
832                   &Private->ExitBootServiceEvent\r
833                   );\r
834   if (EFI_ERROR (Status)) {\r
835     FreePool (Private);\r
836     return NULL;\r
837   }\r
838 \r
839   Private->ExtScsiPassThruHandle = NULL;\r
840   CopyMem(&Private->IScsiExtScsiPassThru, &gIScsiExtScsiPassThruProtocolTemplate, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL));\r
841 \r
842   //\r
843   // 0 is designated to the TargetId, so use another value for the AdapterId.\r
844   //\r
845   Private->ExtScsiPassThruMode.AdapterId  = 2;\r
846   Private->ExtScsiPassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;\r
847   Private->ExtScsiPassThruMode.IoAlign    = 4;\r
848   Private->IScsiExtScsiPassThru.Mode      = &Private->ExtScsiPassThruMode;\r
849 \r
850   return Private;\r
851 }\r
852 \r
853 \r
854 /**\r
855   Clean the iSCSI driver data.\r
856 \r
857   @param[in]  Private The iSCSI driver data.\r
858 \r
859 **/\r
860 VOID\r
861 IScsiCleanDriverData (\r
862   IN ISCSI_DRIVER_DATA  *Private\r
863   )\r
864 {\r
865   EFI_STATUS            Status;\r
866 \r
867   if (Private->DevicePath != NULL) {\r
868     gBS->UninstallProtocolInterface (\r
869            Private->ExtScsiPassThruHandle,\r
870            &gEfiDevicePathProtocolGuid,\r
871            Private->DevicePath\r
872            );\r
873 \r
874     FreePool (Private->DevicePath);\r
875   }\r
876 \r
877   if (Private->ExtScsiPassThruHandle != NULL) {\r
878     Status = gBS->UninstallProtocolInterface (\r
879                     Private->ExtScsiPassThruHandle,\r
880                     &gEfiExtScsiPassThruProtocolGuid,\r
881                     &Private->IScsiExtScsiPassThru\r
882                     );\r
883     if (!EFI_ERROR (Status)) {\r
884       mPrivate->OneSessionEstablished = FALSE;\r
885     }\r
886   }\r
887 \r
888   gBS->CloseEvent (Private->ExitBootServiceEvent);\r
889 \r
890   FreePool (Private);\r
891 }\r
892 \r
893 /**\r
894   Check wheather the Controller handle is configured to use DHCP protocol.\r
895 \r
896   @param[in]  Controller           The handle of the controller.\r
897   @param[in]  IpVersion            IP_VERSION_4 or IP_VERSION_6.\r
898   \r
899   @retval TRUE                     The handle of the controller need the Dhcp protocol.\r
900   @retval FALSE                    The handle of the controller does not need the Dhcp protocol.\r
901   \r
902 **/\r
903 BOOLEAN\r
904 IScsiDhcpIsConfigured (\r
905   IN EFI_HANDLE  Controller,\r
906   IN UINT8       IpVersion\r
907   )\r
908 {\r
909   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptTmp;\r
910   UINT8                       *AttemptConfigOrder;\r
911   UINTN                       AttemptConfigOrderSize;\r
912   UINTN                       Index;\r
913   EFI_STATUS                  Status;\r
914   EFI_MAC_ADDRESS             MacAddr;\r
915   UINTN                       HwAddressSize;\r
916   UINT16                      VlanId;\r
917   CHAR16                      MacString[ISCSI_MAX_MAC_STRING_LEN];\r
918   CHAR16                      AttemptName[ISCSI_NAME_IFR_MAX_SIZE];\r
919   \r
920   AttemptConfigOrder = IScsiGetVariableAndSize (\r
921                          L"AttemptOrder",\r
922                          &gIScsiConfigGuid,\r
923                          &AttemptConfigOrderSize\r
924                          );\r
925   if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) {\r
926     return FALSE;\r
927   }\r
928   \r
929   //\r
930   // Get MAC address of this network device.\r
931   //\r
932   Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);\r
933   if(EFI_ERROR (Status)) {\r
934     return FALSE;\r
935   }\r
936   //\r
937   // Get VLAN ID of this network device.\r
938   //\r
939   VlanId = NetLibGetVlanId (Controller);\r
940   IScsiMacAddrToStr (&MacAddr, (UINT32) HwAddressSize, VlanId, MacString);\r
941   \r
942   for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {\r
943     UnicodeSPrint (\r
944       AttemptName,\r
945       (UINTN) 128,\r
946       L"%s%d",\r
947       MacString,\r
948       (UINTN) AttemptConfigOrder[Index]\r
949       );\r
950     Status = GetVariable2 (\r
951                AttemptName,\r
952                &gEfiIScsiInitiatorNameProtocolGuid,\r
953                (VOID**)&AttemptTmp,\r
954                NULL\r
955                );\r
956     if(EFI_ERROR (Status)) {\r
957       continue;\r
958     }\r
959     ASSERT (AttemptConfigOrder[Index] == AttemptTmp->AttemptConfigIndex);\r
960 \r
961     if (AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED) {\r
962       FreePool (AttemptTmp);\r
963       continue;\r
964     }\r
965 \r
966     if (AttemptTmp->SessionConfigData.IpMode != IP_MODE_AUTOCONFIG && \r
967         AttemptTmp->SessionConfigData.IpMode != ((IpVersion == IP_VERSION_4) ? IP_MODE_IP4 : IP_MODE_IP6)) {\r
968       FreePool (AttemptTmp);\r
969       continue;\r
970     }\r
971     \r
972     if(AttemptTmp->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG ||\r
973        AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp == TRUE ||\r
974        AttemptTmp->SessionConfigData.TargetInfoFromDhcp == TRUE) { \r
975       FreePool (AttemptTmp);\r
976       FreePool (AttemptConfigOrder);\r
977       return TRUE;\r
978     }\r
979 \r
980     FreePool (AttemptTmp);\r
981   }\r
982   \r
983   FreePool (AttemptConfigOrder);\r
984   return FALSE;\r
985 }\r
986 \r
987 /**\r
988   Get the various configuration data.\r
989 \r
990   @param[in]  Private   The iSCSI driver data.\r
991 \r
992   @retval EFI_SUCCESS            The configuration data is retrieved.\r
993   @retval EFI_NOT_FOUND          This iSCSI driver is not configured yet.\r
994 \r
995 **/\r
996 EFI_STATUS\r
997 IScsiGetConfigData (\r
998   IN ISCSI_DRIVER_DATA  *Private\r
999   )\r
1000 {\r
1001   EFI_STATUS                  Status;\r
1002   CHAR16                      MacString[ISCSI_MAX_MAC_STRING_LEN];\r
1003   UINTN                       Index;\r
1004   ISCSI_NIC_INFO              *NicInfo;\r
1005   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;\r
1006   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptTmp;\r
1007   UINT8                       *AttemptConfigOrder;\r
1008   UINTN                       AttemptConfigOrderSize;\r
1009   CHAR16                      IScsiMode[64];\r
1010   CHAR16                      IpMode[64];\r
1011 \r
1012   //\r
1013   // There should be at least one attempt configured.\r
1014   //\r
1015   AttemptConfigOrder = IScsiGetVariableAndSize (\r
1016                          L"AttemptOrder",\r
1017                          &gIScsiConfigGuid,\r
1018                          &AttemptConfigOrderSize\r
1019                          );\r
1020   if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) {\r
1021     return EFI_NOT_FOUND;\r
1022   }\r
1023 \r
1024   //\r
1025   // Get the iSCSI Initiator Name.\r
1026   //\r
1027   mPrivate->InitiatorNameLength  = ISCSI_NAME_MAX_SIZE;\r
1028   Status = gIScsiInitiatorName.Get (\r
1029                                  &gIScsiInitiatorName,\r
1030                                  &mPrivate->InitiatorNameLength,\r
1031                                  mPrivate->InitiatorName\r
1032                                  );\r
1033   if (EFI_ERROR (Status)) {\r
1034     return Status;\r
1035   }\r
1036 \r
1037   //\r
1038   // Get the normal configuration.\r
1039   //\r
1040   for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {\r
1041 \r
1042     //\r
1043     // Check whether the attempt exists in AttemptConfig.\r
1044     //\r
1045     AttemptTmp = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]);    \r
1046     if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED) {\r
1047       continue;\r
1048     } else if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled != ISCSI_DISABLED) {\r
1049       //\r
1050       // Check the autoconfig path to see whether it should be retried.\r
1051       //\r
1052       if (AttemptTmp->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&\r
1053           AttemptTmp->AutoConfigureMode != IP_MODE_AUTOCONFIG_SUCCESS) {\r
1054         if (mPrivate->Ipv6Flag &&\r
1055             AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6) {\r
1056           //\r
1057           // Autoconfigure for IP6 already attempted but failed. Do not try again.\r
1058           //\r
1059           continue;\r
1060         } else if (!mPrivate->Ipv6Flag &&\r
1061                    AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4) {\r
1062           //\r
1063           // Autoconfigure for IP4  already attempted but failed. Do not try again.\r
1064           //\r
1065           continue;\r
1066         } else {\r
1067           //\r
1068           // Try another approach for this autoconfigure path.\r
1069           //\r
1070           AttemptTmp->AutoConfigureMode =\r
1071             (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);\r
1072           AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp = TRUE;\r
1073           AttemptTmp->SessionConfigData.TargetInfoFromDhcp    = TRUE;\r
1074           AttemptTmp->DhcpSuccess                             = FALSE;\r
1075 \r
1076           //\r
1077           // Get some information from the dhcp server.\r
1078           //\r
1079           if (!mPrivate->Ipv6Flag) {\r
1080             Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);\r
1081             if (!EFI_ERROR (Status)) {\r
1082               AttemptTmp->DhcpSuccess = TRUE;\r
1083             }\r
1084           } else {\r
1085             Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);\r
1086             if (!EFI_ERROR (Status)) {\r
1087               AttemptTmp->DhcpSuccess = TRUE;\r
1088             }\r
1089           }\r
1090 \r
1091           //\r
1092           // Refresh the state of this attempt to NVR.\r
1093           //\r
1094           AsciiStrToUnicodeStr (AttemptTmp->MacString, MacString);\r
1095           UnicodeSPrint (\r
1096             mPrivate->PortString,\r
1097             (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
1098             L"%s%d",\r
1099             MacString,\r
1100             (UINTN) AttemptTmp->AttemptConfigIndex\r
1101             );\r
1102 \r
1103           gRT->SetVariable (\r
1104                  mPrivate->PortString,\r
1105                  &gEfiIScsiInitiatorNameProtocolGuid,\r
1106                  ISCSI_CONFIG_VAR_ATTR,\r
1107                  sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),\r
1108                  AttemptTmp\r
1109                  );\r
1110 \r
1111           continue;\r
1112         }\r
1113       } else if (AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp && !AttemptTmp->ValidPath) {\r
1114         //\r
1115         // Get DHCP information for already added, but failed, attempt.\r
1116         //\r
1117         AttemptTmp->DhcpSuccess = FALSE;\r
1118         if (!mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP4)) {\r
1119           Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);\r
1120           if (!EFI_ERROR (Status)) {\r
1121             AttemptTmp->DhcpSuccess = TRUE;\r
1122           }\r
1123         } else if (mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP6)) {\r
1124           Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);\r
1125           if (!EFI_ERROR (Status)) {\r
1126             AttemptTmp->DhcpSuccess = TRUE;\r
1127           }\r
1128         }\r
1129 \r
1130         //\r
1131         // Refresh the state of this attempt to NVR.\r
1132         //\r
1133         AsciiStrToUnicodeStr (AttemptTmp->MacString, MacString);\r
1134         UnicodeSPrint (\r
1135           mPrivate->PortString,\r
1136           (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
1137           L"%s%d",\r
1138           MacString,\r
1139           (UINTN) AttemptTmp->AttemptConfigIndex\r
1140           );\r
1141 \r
1142         gRT->SetVariable (\r
1143                mPrivate->PortString,\r
1144                &gEfiIScsiInitiatorNameProtocolGuid,\r
1145                ISCSI_CONFIG_VAR_ATTR,\r
1146                sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),\r
1147                AttemptTmp\r
1148                );\r
1149 \r
1150         continue;\r
1151 \r
1152       } else {\r
1153         continue;\r
1154       }\r
1155     }\r
1156 \r
1157     //\r
1158     // This attempt does not exist in AttemptConfig. Try to add a new one.\r
1159     //\r
1160 \r
1161     NicInfo = IScsiGetNicInfoByIndex (mPrivate->CurrentNic);\r
1162     ASSERT (NicInfo != NULL);\r
1163     IScsiMacAddrToStr (&NicInfo->PermanentAddress, NicInfo->HwAddressSize, NicInfo->VlanId, MacString);\r
1164     UnicodeSPrint (\r
1165       mPrivate->PortString,\r
1166       (UINTN) 128,\r
1167       L"%s%d",\r
1168       MacString,\r
1169       (UINTN) AttemptConfigOrder[Index]\r
1170       );\r
1171 \r
1172     GetVariable2 (\r
1173                  mPrivate->PortString,\r
1174                  &gEfiIScsiInitiatorNameProtocolGuid,\r
1175                  (VOID**)&AttemptConfigData,\r
1176                  NULL\r
1177                  );\r
1178 \r
1179     if (AttemptConfigData == NULL) {\r
1180       continue;\r
1181     }\r
1182 \r
1183     ASSERT (AttemptConfigOrder[Index] == AttemptConfigData->AttemptConfigIndex);\r
1184 \r
1185     AttemptConfigData->NicIndex      = NicInfo->NicIndex;\r
1186     AttemptConfigData->DhcpSuccess   = FALSE;\r
1187     AttemptConfigData->ValidiBFTPath = (BOOLEAN) (mPrivate->EnableMpio ? TRUE : FALSE);\r
1188     AttemptConfigData->ValidPath     = FALSE;\r
1189 \r
1190     if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {\r
1191       AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp = TRUE;\r
1192       AttemptConfigData->SessionConfigData.TargetInfoFromDhcp    = TRUE;\r
1193 \r
1194       AttemptConfigData->AutoConfigureMode =\r
1195         (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);\r
1196     }\r
1197     \r
1198     //\r
1199     // Get some information from dhcp server.\r
1200     //\r
1201     if (AttemptConfigData->SessionConfigData.Enabled != ISCSI_DISABLED &&\r
1202         AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp) {\r
1203 \r
1204       if (!mPrivate->Ipv6Flag &&\r
1205           (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4 ||\r
1206            AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4)) {\r
1207         Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptConfigData);\r
1208         if (!EFI_ERROR (Status)) {\r
1209           AttemptConfigData->DhcpSuccess = TRUE;\r
1210         }\r
1211       } else if (mPrivate->Ipv6Flag &&\r
1212                 (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6 ||\r
1213                  AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6)) {\r
1214         Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptConfigData);\r
1215         if (!EFI_ERROR (Status)) {\r
1216           AttemptConfigData->DhcpSuccess = TRUE;\r
1217         }\r
1218       }\r
1219 \r
1220       //\r
1221       // Refresh the state of this attempt to NVR.\r
1222       //\r
1223       AsciiStrToUnicodeStr (AttemptConfigData->MacString, MacString);\r
1224       UnicodeSPrint (\r
1225         mPrivate->PortString,\r
1226         (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
1227         L"%s%d",\r
1228         MacString,\r
1229         (UINTN) AttemptConfigData->AttemptConfigIndex\r
1230         );\r
1231 \r
1232       gRT->SetVariable (\r
1233              mPrivate->PortString,\r
1234              &gEfiIScsiInitiatorNameProtocolGuid,\r
1235              ISCSI_CONFIG_VAR_ATTR,\r
1236              sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),\r
1237              AttemptConfigData\r
1238              );\r
1239     }\r
1240 \r
1241     //\r
1242     // Update Attempt Help Info.\r
1243     //\r
1244 \r
1245     if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_DISABLED) {\r
1246       UnicodeSPrint (IScsiMode, 64, L"Disabled");\r
1247     } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {\r
1248       UnicodeSPrint (IScsiMode, 64, L"Enabled");\r
1249     } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {\r
1250       UnicodeSPrint (IScsiMode, 64, L"Enabled for MPIO");\r
1251     }\r
1252 \r
1253     if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4) {\r
1254       UnicodeSPrint (IpMode, 64, L"IP4");\r
1255     } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6) {\r
1256       UnicodeSPrint (IpMode, 64, L"IP6");\r
1257     } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {\r
1258       UnicodeSPrint (IpMode, 64, L"Autoconfigure");\r
1259     }\r
1260 \r
1261     UnicodeSPrint (\r
1262       mPrivate->PortString,\r
1263       (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
1264       L"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s",\r
1265       MacString,\r
1266       NicInfo->BusNumber,\r
1267       NicInfo->DeviceNumber,\r
1268       NicInfo->FunctionNumber,\r
1269       IScsiMode,\r
1270       IpMode\r
1271       );\r
1272 \r
1273     AttemptConfigData->AttemptTitleHelpToken = HiiSetString (\r
1274                                                  mCallbackInfo->RegisteredHandle,\r
1275                                                  0,\r
1276                                                  mPrivate->PortString,\r
1277                                                  NULL\r
1278                                                  );\r
1279     ASSERT (AttemptConfigData->AttemptTitleHelpToken != 0);\r
1280 \r
1281     //\r
1282     // Record the attempt in global link list.\r
1283     //\r
1284     InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);\r
1285     mPrivate->AttemptCount++;\r
1286 \r
1287     if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {\r
1288       mPrivate->MpioCount++;\r
1289       mPrivate->EnableMpio = TRUE;\r
1290 \r
1291       if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB) {\r
1292         mPrivate->Krb5MpioCount++;\r
1293       }\r
1294     } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {\r
1295       mPrivate->SinglePathCount++;\r
1296     }\r
1297   }\r
1298 \r
1299   //\r
1300   // Reorder the AttemptConfig by the configured order.\r
1301   //\r
1302   for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {\r
1303     AttemptConfigData = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]);\r
1304     if (AttemptConfigData == NULL) {\r
1305       continue;\r
1306     }\r
1307 \r
1308     RemoveEntryList (&AttemptConfigData->Link);\r
1309     InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);\r
1310   }\r
1311 \r
1312   //\r
1313   // Update the Main Form.\r
1314   //\r
1315   IScsiConfigUpdateAttempt ();\r
1316 \r
1317   FreePool (AttemptConfigOrder);\r
1318 \r
1319   //\r
1320   //  There should be at least one attempt configuration.\r
1321   //\r
1322   if (!mPrivate->EnableMpio) {\r
1323     if (mPrivate->SinglePathCount == 0) {\r
1324       return EFI_NOT_FOUND;\r
1325     }\r
1326     mPrivate->ValidSinglePathCount = mPrivate->SinglePathCount;\r
1327   }\r
1328 \r
1329   return EFI_SUCCESS;\r
1330 }\r
1331 \r
1332 \r
1333 /**\r
1334   Get the device path of the iSCSI tcp connection and update it.\r
1335 \r
1336   @param  Session                The iSCSI session.\r
1337 \r
1338   @return The updated device path.\r
1339   @retval NULL Other errors as indicated.\r
1340 \r
1341 **/\r
1342 EFI_DEVICE_PATH_PROTOCOL *\r
1343 IScsiGetTcpConnDevicePath (\r
1344   IN ISCSI_SESSION      *Session\r
1345   )\r
1346 {\r
1347   ISCSI_CONNECTION          *Conn;\r
1348   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
1349   EFI_STATUS                Status;\r
1350   EFI_DEV_PATH              *DPathNode;\r
1351 \r
1352   if (Session->State != SESSION_STATE_LOGGED_IN) {\r
1353     return NULL;\r
1354   }\r
1355 \r
1356   Conn = NET_LIST_USER_STRUCT_S (\r
1357            Session->Conns.ForwardLink,\r
1358            ISCSI_CONNECTION,\r
1359            Link,\r
1360            ISCSI_CONNECTION_SIGNATURE\r
1361            );\r
1362 \r
1363   Status = gBS->HandleProtocol (\r
1364                   Conn->TcpIo.Handle,\r
1365                   &gEfiDevicePathProtocolGuid,\r
1366                   (VOID **) &DevicePath\r
1367                   );  \r
1368   if (EFI_ERROR (Status)) {\r
1369     return NULL;\r
1370   }\r
1371   //\r
1372   // Duplicate it.\r
1373   //\r
1374   DevicePath  = DuplicateDevicePath (DevicePath);\r
1375   if (DevicePath == NULL) {\r
1376     return NULL;\r
1377   }\r
1378 \r
1379   DPathNode   = (EFI_DEV_PATH *) DevicePath;\r
1380 \r
1381   while (!IsDevicePathEnd (&DPathNode->DevPath)) {\r
1382     if (DevicePathType (&DPathNode->DevPath) == MESSAGING_DEVICE_PATH) {\r
1383       if (!Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv4_DP) {\r
1384         DPathNode->Ipv4.LocalPort       = 0;\r
1385 \r
1386         DPathNode->Ipv4.StaticIpAddress = \r
1387           (BOOLEAN) (!Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp);\r
1388 \r
1389         IP4_COPY_ADDRESS (\r
1390           &DPathNode->Ipv4.GatewayIpAddress,\r
1391           &Session->ConfigData->SessionConfigData.Gateway\r
1392           );\r
1393 \r
1394         IP4_COPY_ADDRESS (\r
1395           &DPathNode->Ipv4.SubnetMask,\r
1396           &Session->ConfigData->SessionConfigData.SubnetMask\r
1397           );\r
1398         break;\r
1399       } else if (Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv6_DP) {\r
1400         DPathNode->Ipv6.LocalPort       = 0;\r
1401         DPathNode->Ipv6.IpAddressOrigin = 0;\r
1402         DPathNode->Ipv6.PrefixLength    = IP6_PREFIX_LENGTH;\r
1403         ZeroMem (&DPathNode->Ipv6.GatewayIpAddress, sizeof (EFI_IPv6_ADDRESS));\r
1404         break;\r
1405       }\r
1406     }\r
1407 \r
1408     DPathNode = (EFI_DEV_PATH *) NextDevicePathNode (&DPathNode->DevPath);\r
1409   }\r
1410 \r
1411   return DevicePath;\r
1412 }\r
1413 \r
1414 \r
1415 /**\r
1416   Abort the session when the transition from BS to RT is initiated.\r
1417 \r
1418   @param[in]   Event  The event signaled.\r
1419   @param[in]  Context The iSCSI driver data.\r
1420 \r
1421 **/\r
1422 VOID\r
1423 EFIAPI\r
1424 IScsiOnExitBootService (\r
1425   IN EFI_EVENT  Event,\r
1426   IN VOID       *Context\r
1427   )\r
1428 {\r
1429   ISCSI_DRIVER_DATA *Private;\r
1430 \r
1431   Private = (ISCSI_DRIVER_DATA *) Context;\r
1432   gBS->CloseEvent (Private->ExitBootServiceEvent);\r
1433 \r
1434   if (Private->Session != NULL) {\r
1435     IScsiSessionAbort (Private->Session);\r
1436   }\r
1437 }\r