971011eac52884a636eb7cf167dd2501da5c6148
[mirror_edk2.git] / NetworkPkg / IScsiDxe / IScsiMisc.c
1 /** @file\r
2   Miscellaneous routines for iSCSI driver.\r
3 \r
4 Copyright (c) 2004 - 2012, 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 /**\r
895   Get the various configuration data.\r
896 \r
897   @param[in]  Private   The iSCSI driver data.\r
898 \r
899   @retval EFI_SUCCESS            The configuration data is retrieved.\r
900   @retval EFI_NOT_FOUND          This iSCSI driver is not configured yet.\r
901 \r
902 **/\r
903 EFI_STATUS\r
904 IScsiGetConfigData (\r
905   IN ISCSI_DRIVER_DATA  *Private\r
906   )\r
907 {\r
908   EFI_STATUS                  Status;\r
909   CHAR16                      MacString[ISCSI_MAX_MAC_STRING_LEN];\r
910   UINTN                       Index;\r
911   ISCSI_NIC_INFO              *NicInfo;\r
912   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;\r
913   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptTmp;\r
914   UINT8                       *AttemptConfigOrder;\r
915   UINTN                       AttemptConfigOrderSize;\r
916   CHAR16                      IScsiMode[64];\r
917   CHAR16                      IpMode[64];\r
918 \r
919   //\r
920   // There should be at least one attempt configured.\r
921   //\r
922   AttemptConfigOrder = IScsiGetVariableAndSize (\r
923                          L"AttemptOrder",\r
924                          &gIScsiConfigGuid,\r
925                          &AttemptConfigOrderSize\r
926                          );\r
927   if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) {\r
928     return EFI_NOT_FOUND;\r
929   }\r
930 \r
931   //\r
932   // Get the iSCSI Initiator Name.\r
933   //\r
934   mPrivate->InitiatorNameLength  = ISCSI_NAME_MAX_SIZE;\r
935   Status = gIScsiInitiatorName.Get (\r
936                                  &gIScsiInitiatorName,\r
937                                  &mPrivate->InitiatorNameLength,\r
938                                  mPrivate->InitiatorName\r
939                                  );\r
940   if (EFI_ERROR (Status)) {\r
941     return Status;\r
942   }\r
943 \r
944   //\r
945   // Get the normal configuration.\r
946   //\r
947   for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {\r
948 \r
949     //\r
950     // Check whether the attempt exists in AttemptConfig.\r
951     //\r
952     AttemptTmp = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]);    \r
953     if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED) {\r
954       continue;\r
955     } else if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled != ISCSI_DISABLED) {\r
956       //\r
957       // Check the autoconfig path to see whether it should be retried.\r
958       //\r
959       if (AttemptTmp->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&\r
960           AttemptTmp->AutoConfigureMode != IP_MODE_AUTOCONFIG_SUCCESS) {\r
961         if (mPrivate->Ipv6Flag &&\r
962             AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6) {\r
963           //\r
964           // Autoconfigure for IP6 already attempted but failed. Do not try again.\r
965           //\r
966           continue;\r
967         } else if (!mPrivate->Ipv6Flag &&\r
968                    AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4) {\r
969           //\r
970           // Autoconfigure for IP4  already attempted but failed. Do not try again.\r
971           //\r
972           continue;\r
973         } else {\r
974           //\r
975           // Try another approach for this autoconfigure path.\r
976           //\r
977           AttemptTmp->AutoConfigureMode =\r
978             (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);\r
979           AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp = TRUE;\r
980           AttemptTmp->SessionConfigData.TargetInfoFromDhcp    = TRUE;\r
981           AttemptTmp->DhcpSuccess                             = FALSE;\r
982 \r
983           //\r
984           // Get some information from the dhcp server.\r
985           //\r
986           if (!mPrivate->Ipv6Flag) {\r
987             Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);\r
988             if (!EFI_ERROR (Status)) {\r
989               AttemptTmp->DhcpSuccess = TRUE;\r
990             }\r
991           } else {\r
992             Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);\r
993             if (!EFI_ERROR (Status)) {\r
994               AttemptTmp->DhcpSuccess = TRUE;\r
995             }\r
996           }\r
997 \r
998           //\r
999           // Refresh the state of this attempt to NVR.\r
1000           //\r
1001           AsciiStrToUnicodeStr (AttemptTmp->MacString, MacString);\r
1002           UnicodeSPrint (\r
1003             mPrivate->PortString,\r
1004             (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
1005             L"%s%d",\r
1006             MacString,\r
1007             (UINTN) AttemptTmp->AttemptConfigIndex\r
1008             );\r
1009 \r
1010           gRT->SetVariable (\r
1011                  mPrivate->PortString,\r
1012                  &gEfiIScsiInitiatorNameProtocolGuid,\r
1013                  ISCSI_CONFIG_VAR_ATTR,\r
1014                  sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),\r
1015                  AttemptTmp\r
1016                  );\r
1017 \r
1018           continue;\r
1019         }\r
1020       } else if (AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp && !AttemptTmp->ValidPath) {\r
1021         //\r
1022         // Get DHCP information for already added, but failed, attempt.\r
1023         //\r
1024         AttemptTmp->DhcpSuccess = FALSE;\r
1025         if (!mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP4)) {\r
1026           Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);\r
1027           if (!EFI_ERROR (Status)) {\r
1028             AttemptTmp->DhcpSuccess = TRUE;\r
1029           }\r
1030         } else if (mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP6)) {\r
1031           Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);\r
1032           if (!EFI_ERROR (Status)) {\r
1033             AttemptTmp->DhcpSuccess = TRUE;\r
1034           }\r
1035         }\r
1036 \r
1037         //\r
1038         // Refresh the state of this attempt to NVR.\r
1039         //\r
1040         AsciiStrToUnicodeStr (AttemptTmp->MacString, MacString);\r
1041         UnicodeSPrint (\r
1042           mPrivate->PortString,\r
1043           (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
1044           L"%s%d",\r
1045           MacString,\r
1046           (UINTN) AttemptTmp->AttemptConfigIndex\r
1047           );\r
1048 \r
1049         gRT->SetVariable (\r
1050                mPrivate->PortString,\r
1051                &gEfiIScsiInitiatorNameProtocolGuid,\r
1052                ISCSI_CONFIG_VAR_ATTR,\r
1053                sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),\r
1054                AttemptTmp\r
1055                );\r
1056 \r
1057         continue;\r
1058 \r
1059       } else {\r
1060         continue;\r
1061       }\r
1062     }\r
1063 \r
1064     //\r
1065     // This attempt does not exist in AttemptConfig. Try to add a new one.\r
1066     //\r
1067 \r
1068     NicInfo = IScsiGetNicInfoByIndex (mPrivate->CurrentNic);\r
1069     ASSERT (NicInfo != NULL);\r
1070     IScsiMacAddrToStr (&NicInfo->PermanentAddress, NicInfo->HwAddressSize, NicInfo->VlanId, MacString);\r
1071     UnicodeSPrint (\r
1072       mPrivate->PortString,\r
1073       (UINTN) 128,\r
1074       L"%s%d",\r
1075       MacString,\r
1076       (UINTN) AttemptConfigOrder[Index]\r
1077       );\r
1078 \r
1079     GetVariable2 (\r
1080                  mPrivate->PortString,\r
1081                  &gEfiIScsiInitiatorNameProtocolGuid,\r
1082                  (VOID**)&AttemptConfigData,\r
1083                  NULL\r
1084                  );\r
1085 \r
1086     if (AttemptConfigData == NULL) {\r
1087       continue;\r
1088     }\r
1089 \r
1090     ASSERT (AttemptConfigOrder[Index] == AttemptConfigData->AttemptConfigIndex);\r
1091 \r
1092     AttemptConfigData->NicIndex      = NicInfo->NicIndex;\r
1093     AttemptConfigData->DhcpSuccess   = FALSE;\r
1094     AttemptConfigData->ValidiBFTPath = (BOOLEAN) (mPrivate->EnableMpio ? TRUE : FALSE);\r
1095     AttemptConfigData->ValidPath     = FALSE;\r
1096 \r
1097     if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {\r
1098       AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp = TRUE;\r
1099       AttemptConfigData->SessionConfigData.TargetInfoFromDhcp    = TRUE;\r
1100 \r
1101       AttemptConfigData->AutoConfigureMode =\r
1102         (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);\r
1103     }\r
1104     \r
1105     //\r
1106     // Get some information from dhcp server.\r
1107     //\r
1108     if (AttemptConfigData->SessionConfigData.Enabled != ISCSI_DISABLED &&\r
1109         AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp) {\r
1110 \r
1111       if (!mPrivate->Ipv6Flag &&\r
1112           (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4 ||\r
1113            AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4)) {\r
1114         Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptConfigData);\r
1115         if (!EFI_ERROR (Status)) {\r
1116           AttemptConfigData->DhcpSuccess = TRUE;\r
1117         }\r
1118       } else if (mPrivate->Ipv6Flag &&\r
1119                 (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6 ||\r
1120                  AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6)) {\r
1121         Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptConfigData);\r
1122         if (!EFI_ERROR (Status)) {\r
1123           AttemptConfigData->DhcpSuccess = TRUE;\r
1124         }\r
1125       }\r
1126 \r
1127       //\r
1128       // Refresh the state of this attempt to NVR.\r
1129       //\r
1130       AsciiStrToUnicodeStr (AttemptConfigData->MacString, MacString);\r
1131       UnicodeSPrint (\r
1132         mPrivate->PortString,\r
1133         (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
1134         L"%s%d",\r
1135         MacString,\r
1136         (UINTN) AttemptConfigData->AttemptConfigIndex\r
1137         );\r
1138 \r
1139       gRT->SetVariable (\r
1140              mPrivate->PortString,\r
1141              &gEfiIScsiInitiatorNameProtocolGuid,\r
1142              ISCSI_CONFIG_VAR_ATTR,\r
1143              sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),\r
1144              AttemptConfigData\r
1145              );\r
1146     }\r
1147 \r
1148     //\r
1149     // Update Attempt Help Info.\r
1150     //\r
1151 \r
1152     if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_DISABLED) {\r
1153       UnicodeSPrint (IScsiMode, 64, L"Disabled");\r
1154     } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {\r
1155       UnicodeSPrint (IScsiMode, 64, L"Enabled");\r
1156     } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {\r
1157       UnicodeSPrint (IScsiMode, 64, L"Enabled for MPIO");\r
1158     }\r
1159 \r
1160     if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4) {\r
1161       UnicodeSPrint (IpMode, 64, L"IP4");\r
1162     } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6) {\r
1163       UnicodeSPrint (IpMode, 64, L"IP6");\r
1164     } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {\r
1165       UnicodeSPrint (IpMode, 64, L"Autoconfigure");\r
1166     }\r
1167 \r
1168     UnicodeSPrint (\r
1169       mPrivate->PortString,\r
1170       (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
1171       L"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s",\r
1172       MacString,\r
1173       NicInfo->BusNumber,\r
1174       NicInfo->DeviceNumber,\r
1175       NicInfo->FunctionNumber,\r
1176       IScsiMode,\r
1177       IpMode\r
1178       );\r
1179 \r
1180     AttemptConfigData->AttemptTitleHelpToken = HiiSetString (\r
1181                                                  mCallbackInfo->RegisteredHandle,\r
1182                                                  0,\r
1183                                                  mPrivate->PortString,\r
1184                                                  NULL\r
1185                                                  );\r
1186     ASSERT (AttemptConfigData->AttemptTitleHelpToken != 0);\r
1187 \r
1188     //\r
1189     // Record the attempt in global link list.\r
1190     //\r
1191     InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);\r
1192     mPrivate->AttemptCount++;\r
1193 \r
1194     if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {\r
1195       mPrivate->MpioCount++;\r
1196       mPrivate->EnableMpio = TRUE;\r
1197 \r
1198       if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB) {\r
1199         mPrivate->Krb5MpioCount++;\r
1200       }\r
1201     } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {\r
1202       mPrivate->SinglePathCount++;\r
1203     }\r
1204   }\r
1205 \r
1206   //\r
1207   // Reorder the AttemptConfig by the configured order.\r
1208   //\r
1209   for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {\r
1210     AttemptConfigData = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]);\r
1211     if (AttemptConfigData == NULL) {\r
1212       continue;\r
1213     }\r
1214 \r
1215     RemoveEntryList (&AttemptConfigData->Link);\r
1216     InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);\r
1217   }\r
1218 \r
1219   //\r
1220   // Update the Main Form.\r
1221   //\r
1222   IScsiConfigUpdateAttempt ();\r
1223 \r
1224   FreePool (AttemptConfigOrder);\r
1225 \r
1226   //\r
1227   //  There should be at least one attempt configuration.\r
1228   //\r
1229   if (!mPrivate->EnableMpio) {\r
1230     if (mPrivate->SinglePathCount == 0) {\r
1231       return EFI_NOT_FOUND;\r
1232     }\r
1233     mPrivate->ValidSinglePathCount = mPrivate->SinglePathCount;\r
1234   }\r
1235 \r
1236   return EFI_SUCCESS;\r
1237 }\r
1238 \r
1239 \r
1240 /**\r
1241   Get the device path of the iSCSI tcp connection and update it.\r
1242 \r
1243   @param  Session                The iSCSI session.\r
1244 \r
1245   @return The updated device path.\r
1246   @retval NULL Other errors as indicated.\r
1247 \r
1248 **/\r
1249 EFI_DEVICE_PATH_PROTOCOL *\r
1250 IScsiGetTcpConnDevicePath (\r
1251   IN ISCSI_SESSION      *Session\r
1252   )\r
1253 {\r
1254   ISCSI_CONNECTION          *Conn;\r
1255   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
1256   EFI_STATUS                Status;\r
1257   EFI_DEV_PATH              *DPathNode;\r
1258 \r
1259   if (Session->State != SESSION_STATE_LOGGED_IN) {\r
1260     return NULL;\r
1261   }\r
1262 \r
1263   Conn = NET_LIST_USER_STRUCT_S (\r
1264            Session->Conns.ForwardLink,\r
1265            ISCSI_CONNECTION,\r
1266            Link,\r
1267            ISCSI_CONNECTION_SIGNATURE\r
1268            );\r
1269 \r
1270   Status = gBS->HandleProtocol (\r
1271                   Conn->TcpIo.Handle,\r
1272                   &gEfiDevicePathProtocolGuid,\r
1273                   (VOID **) &DevicePath\r
1274                   );  \r
1275   if (EFI_ERROR (Status)) {\r
1276     return NULL;\r
1277   }\r
1278   //\r
1279   // Duplicate it.\r
1280   //\r
1281   DevicePath  = DuplicateDevicePath (DevicePath);\r
1282   if (DevicePath == NULL) {\r
1283     return NULL;\r
1284   }\r
1285 \r
1286   DPathNode   = (EFI_DEV_PATH *) DevicePath;\r
1287 \r
1288   while (!IsDevicePathEnd (&DPathNode->DevPath)) {\r
1289     if (DevicePathType (&DPathNode->DevPath) == MESSAGING_DEVICE_PATH) {\r
1290       if (!Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv4_DP) {\r
1291         DPathNode->Ipv4.LocalPort       = 0;\r
1292 \r
1293         DPathNode->Ipv4.StaticIpAddress = \r
1294           (BOOLEAN) (!Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp);\r
1295 \r
1296         IP4_COPY_ADDRESS (\r
1297           &DPathNode->Ipv4.GatewayIpAddress,\r
1298           &Session->ConfigData->SessionConfigData.Gateway\r
1299           );\r
1300 \r
1301         IP4_COPY_ADDRESS (\r
1302           &DPathNode->Ipv4.SubnetMask,\r
1303           &Session->ConfigData->SessionConfigData.SubnetMask\r
1304           );\r
1305         break;\r
1306       } else if (Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv6_DP) {\r
1307         DPathNode->Ipv6.LocalPort       = 0;\r
1308         DPathNode->Ipv6.IpAddressOrigin = 0;\r
1309         DPathNode->Ipv6.PrefixLength    = IP6_PREFIX_LENGTH;\r
1310         ZeroMem (&DPathNode->Ipv6.GatewayIpAddress, sizeof (EFI_IPv6_ADDRESS));\r
1311         break;\r
1312       }\r
1313     }\r
1314 \r
1315     DPathNode = (EFI_DEV_PATH *) NextDevicePathNode (&DPathNode->DevPath);\r
1316   }\r
1317 \r
1318   return DevicePath;\r
1319 }\r
1320 \r
1321 \r
1322 /**\r
1323   Abort the session when the transition from BS to RT is initiated.\r
1324 \r
1325   @param[in]   Event  The event signaled.\r
1326   @param[in]  Context The iSCSI driver data.\r
1327 \r
1328 **/\r
1329 VOID\r
1330 EFIAPI\r
1331 IScsiOnExitBootService (\r
1332   IN EFI_EVENT  Event,\r
1333   IN VOID       *Context\r
1334   )\r
1335 {\r
1336   ISCSI_DRIVER_DATA *Private;\r
1337 \r
1338   Private = (ISCSI_DRIVER_DATA *) Context;\r
1339   gBS->CloseEvent (Private->ExitBootServiceEvent);\r
1340 \r
1341   if (Private->Session != NULL) {\r
1342     IScsiSessionAbort (Private->Session);\r
1343   }\r
1344 }\r