]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/IScsiDxe/IScsiMisc.c
Add IScsiDxe driver to NetworkPkg in order to support iSCSI over IPv6 stack and iSCSI...
[mirror_edk2.git] / NetworkPkg / IScsiDxe / IScsiMisc.c
CommitLineData
4c5a5e0c 1/** @file\r
2 Miscellaneous routines for iSCSI driver.\r
3\r
4Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "IScsiImpl.h"\r
16\r
17GLOBAL_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
28VOID\r
29IScsiStrTrim (\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
81UINT8\r
82IScsiGetSubnetMaskPrefixLength (\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
124EFI_STATUS\r
125IScsiAsciiStrToLun (\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
198VOID\r
199IScsiLunToUnicodeStr (\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
250EFI_STATUS\r
251IScsiAsciiStrToIp (\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
286VOID\r
287IScsiMacAddrToStr (\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
325EFI_STATUS\r
326IScsiBinToHex (\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
374EFI_STATUS\r
375IScsiHexToBin (\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
427UINTN\r
428IScsiNetNtoi (\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
449VOID\r
450IScsiGenRandom (\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
475EFI_STATUS\r
476IScsiAddNic (\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
559EFI_STATUS\r
560IScsiRemoveNic (\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 return EFI_SUCCESS;\r
644}\r
645\r
646\r
647/**\r
648 Get the recorded NIC info from global structure by the Index.\r
649\r
650 @param[in] NicIndex The index indicates the position of NIC info.\r
651\r
652 @return Pointer to the NIC info, or NULL if not found.\r
653\r
654**/\r
655ISCSI_NIC_INFO *\r
656IScsiGetNicInfoByIndex (\r
657 IN UINT8 NicIndex\r
658 )\r
659{\r
660 LIST_ENTRY *Entry;\r
661 ISCSI_NIC_INFO *NicInfo;\r
662\r
663 NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {\r
664 NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);\r
665 if (NicInfo->NicIndex == NicIndex) {\r
666 return NicInfo;\r
667 }\r
668 }\r
669\r
670 return NULL;\r
671}\r
672\r
673\r
674/**\r
675 Get the NIC's PCI location and return it accroding to the composited\r
676 format defined in iSCSI Boot Firmware Table.\r
677\r
678 @param[in] Controller The handle of the controller.\r
679 @param[out] Bus The bus number.\r
680 @param[out] Device The device number.\r
681 @param[out] Function The function number.\r
682\r
683 @return The composited representation of the NIC PCI location.\r
684\r
685**/\r
686UINT16\r
687IScsiGetNICPciLocation (\r
688 IN EFI_HANDLE Controller,\r
689 OUT UINTN *Bus,\r
690 OUT UINTN *Device,\r
691 OUT UINTN *Function\r
692 )\r
693{\r
694 EFI_STATUS Status;\r
695 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
696 EFI_HANDLE PciIoHandle;\r
697 EFI_PCI_IO_PROTOCOL *PciIo;\r
698 UINTN Segment;\r
699\r
700 Status = gBS->HandleProtocol (\r
701 Controller,\r
702 &gEfiDevicePathProtocolGuid,\r
703 (VOID **) &DevicePath\r
704 );\r
705 if (EFI_ERROR (Status)) {\r
706 return 0;\r
707 }\r
708\r
709 Status = gBS->LocateDevicePath (\r
710 &gEfiPciIoProtocolGuid,\r
711 &DevicePath,\r
712 &PciIoHandle\r
713 );\r
714 if (EFI_ERROR (Status)) {\r
715 return 0;\r
716 }\r
717\r
718 Status = gBS->HandleProtocol (PciIoHandle, &gEfiPciIoProtocolGuid, (VOID **) &PciIo);\r
719 if (EFI_ERROR (Status)) {\r
720 return 0;\r
721 }\r
722\r
723 Status = PciIo->GetLocation (PciIo, &Segment, Bus, Device, Function);\r
724 if (EFI_ERROR (Status)) {\r
725 return 0;\r
726 }\r
727\r
728 return (UINT16) ((*Bus << 8) | (*Device << 3) | *Function);\r
729}\r
730\r
731\r
732/**\r
733 Read the EFI variable (VendorGuid/Name) and return a dynamically allocated\r
734 buffer, and the size of the buffer. If failure, return NULL.\r
735\r
736 @param[in] Name String part of EFI variable name.\r
737 @param[in] VendorGuid GUID part of EFI variable name.\r
738 @param[out] VariableSize Returns the size of the EFI variable that was read.\r
739\r
740 @return Dynamically allocated memory that contains a copy of the EFI variable.\r
741 @return Caller is responsible freeing the buffer.\r
742 @retval NULL Variable was not read.\r
743\r
744**/\r
745VOID *\r
746IScsiGetVariableAndSize (\r
747 IN CHAR16 *Name,\r
748 IN EFI_GUID *VendorGuid,\r
749 OUT UINTN *VariableSize\r
750 )\r
751{\r
752 EFI_STATUS Status;\r
753 UINTN BufferSize;\r
754 VOID *Buffer;\r
755\r
756 Buffer = NULL;\r
757\r
758 //\r
759 // Pass in a zero size buffer to find the required buffer size.\r
760 //\r
761 BufferSize = 0;\r
762 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);\r
763 if (Status == EFI_BUFFER_TOO_SMALL) {\r
764 //\r
765 // Allocate the buffer to return\r
766 //\r
767 Buffer = AllocateZeroPool (BufferSize);\r
768 if (Buffer == NULL) {\r
769 return NULL;\r
770 }\r
771 //\r
772 // Read variable into the allocated buffer.\r
773 //\r
774 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);\r
775 if (EFI_ERROR (Status)) {\r
776 BufferSize = 0;\r
777 }\r
778 }\r
779\r
780 *VariableSize = BufferSize;\r
781 return Buffer;\r
782}\r
783\r
784\r
785/**\r
786 Create the iSCSI driver data.\r
787\r
788 @param[in] Image The handle of the driver image.\r
789 @param[in] Controller The handle of the controller.\r
790\r
791 @return The iSCSI driver data created.\r
792 @retval NULL Other errors as indicated.\r
793\r
794**/\r
795ISCSI_DRIVER_DATA *\r
796IScsiCreateDriverData (\r
797 IN EFI_HANDLE Image,\r
798 IN EFI_HANDLE Controller\r
799 )\r
800{\r
801 ISCSI_DRIVER_DATA *Private;\r
802 EFI_STATUS Status;\r
803\r
804 Private = AllocateZeroPool (sizeof (ISCSI_DRIVER_DATA));\r
805 if (Private == NULL) {\r
806 return NULL;\r
807 }\r
808\r
809 Private->Signature = ISCSI_DRIVER_DATA_SIGNATURE;\r
810 Private->Image = Image;\r
811 Private->Controller = Controller;\r
812 Private->Session = NULL;\r
813\r
814 //\r
815 // Create an event to be signaled when the BS to RT transition is triggerd so\r
816 // as to abort the iSCSI session.\r
817 //\r
818 Status = gBS->CreateEventEx (\r
819 EVT_NOTIFY_SIGNAL,\r
820 TPL_CALLBACK,\r
821 IScsiOnExitBootService,\r
822 Private,\r
823 &gEfiEventExitBootServicesGuid,\r
824 &Private->ExitBootServiceEvent\r
825 );\r
826 if (EFI_ERROR (Status)) {\r
827 FreePool (Private);\r
828 return NULL;\r
829 }\r
830\r
831 Private->ExtScsiPassThruHandle = NULL;\r
832 CopyMem(&Private->IScsiExtScsiPassThru, &gIScsiExtScsiPassThruProtocolTemplate, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL));\r
833\r
834 //\r
835 // 0 is designated to the TargetId, so use another value for the AdapterId.\r
836 //\r
837 Private->ExtScsiPassThruMode.AdapterId = 2;\r
838 Private->ExtScsiPassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;\r
839 Private->ExtScsiPassThruMode.IoAlign = 4;\r
840 Private->IScsiExtScsiPassThru.Mode = &Private->ExtScsiPassThruMode;\r
841\r
842 return Private;\r
843}\r
844\r
845\r
846/**\r
847 Clean the iSCSI driver data.\r
848\r
849 @param[in] Private The iSCSI driver data.\r
850\r
851**/\r
852VOID\r
853IScsiCleanDriverData (\r
854 IN ISCSI_DRIVER_DATA *Private\r
855 )\r
856{\r
857 EFI_STATUS Status;\r
858\r
859 if (Private->DevicePath != NULL) {\r
860 gBS->UninstallProtocolInterface (\r
861 Private->ExtScsiPassThruHandle,\r
862 &gEfiDevicePathProtocolGuid,\r
863 Private->DevicePath\r
864 );\r
865\r
866 FreePool (Private->DevicePath);\r
867 }\r
868\r
869 if (Private->ExtScsiPassThruHandle != NULL) {\r
870 Status = gBS->UninstallProtocolInterface (\r
871 Private->ExtScsiPassThruHandle,\r
872 &gEfiExtScsiPassThruProtocolGuid,\r
873 &Private->IScsiExtScsiPassThru\r
874 );\r
875 if (!EFI_ERROR (Status)) {\r
876 mPrivate->OneSessionEstablished = FALSE;\r
877 }\r
878 }\r
879\r
880 gBS->CloseEvent (Private->ExitBootServiceEvent);\r
881\r
882 FreePool (Private);\r
883}\r
884\r
885\r
886/**\r
887 Get the various configuration data.\r
888\r
889 @param[in] Private The iSCSI driver data.\r
890\r
891 @retval EFI_SUCCESS The configuration data is retrieved.\r
892 @retval EFI_NOT_FOUND This iSCSI driver is not configured yet.\r
893\r
894**/\r
895EFI_STATUS\r
896IScsiGetConfigData (\r
897 IN ISCSI_DRIVER_DATA *Private\r
898 )\r
899{\r
900 EFI_STATUS Status;\r
901 CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN];\r
902 UINTN Index;\r
903 ISCSI_NIC_INFO *NicInfo;\r
904 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;\r
905 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptTmp;\r
906 UINT8 *AttemptConfigOrder;\r
907 UINTN AttemptConfigOrderSize;\r
908 CHAR16 IScsiMode[64];\r
909 CHAR16 IpMode[64];\r
910\r
911 //\r
912 // There should be at least one attempt configured.\r
913 //\r
914 AttemptConfigOrder = IScsiGetVariableAndSize (\r
915 L"AttemptOrder",\r
916 &mVendorGuid,\r
917 &AttemptConfigOrderSize\r
918 );\r
919 if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) {\r
920 return EFI_NOT_FOUND;\r
921 }\r
922\r
923 //\r
924 // Get the iSCSI Initiator Name.\r
925 //\r
926 mPrivate->InitiatorNameLength = ISCSI_NAME_MAX_SIZE;\r
927 Status = gIScsiInitiatorName.Get (\r
928 &gIScsiInitiatorName,\r
929 &mPrivate->InitiatorNameLength,\r
930 mPrivate->InitiatorName\r
931 );\r
932 if (EFI_ERROR (Status)) {\r
933 return Status;\r
934 }\r
935\r
936 //\r
937 // Get the normal configuration.\r
938 //\r
939 for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {\r
940\r
941 //\r
942 // Check whether the attempt exists in AttemptConfig.\r
943 //\r
944 AttemptTmp = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]); \r
945 if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED) {\r
946 continue;\r
947 } else if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled != ISCSI_DISABLED) {\r
948 //\r
949 // Check the autoconfig path to see whether it should be retried.\r
950 //\r
951 if (AttemptTmp->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&\r
952 AttemptTmp->AutoConfigureMode != IP_MODE_AUTOCONFIG_SUCCESS) {\r
953 if (mPrivate->Ipv6Flag &&\r
954 AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6) {\r
955 //\r
956 // Autoconfigure for IP6 already attempted but failed. Do not try again.\r
957 //\r
958 continue;\r
959 } else if (!mPrivate->Ipv6Flag &&\r
960 AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4) {\r
961 //\r
962 // Autoconfigure for IP4 already attempted but failed. Do not try again.\r
963 //\r
964 continue;\r
965 } else {\r
966 //\r
967 // Try another approach for this autoconfigure path.\r
968 //\r
969 AttemptTmp->AutoConfigureMode =\r
970 (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);\r
971 AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp = TRUE;\r
972 AttemptTmp->SessionConfigData.TargetInfoFromDhcp = TRUE;\r
973 AttemptTmp->DhcpSuccess = FALSE;\r
974\r
975 //\r
976 // Get some information from the dhcp server.\r
977 //\r
978 if (!mPrivate->Ipv6Flag) {\r
979 Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);\r
980 if (!EFI_ERROR (Status)) {\r
981 AttemptTmp->DhcpSuccess = TRUE;\r
982 }\r
983 } else {\r
984 Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);\r
985 if (!EFI_ERROR (Status)) {\r
986 AttemptTmp->DhcpSuccess = TRUE;\r
987 }\r
988 }\r
989\r
990 //\r
991 // Refresh the state of this attempt to NVR.\r
992 //\r
993 AsciiStrToUnicodeStr (AttemptTmp->MacString, MacString);\r
994 UnicodeSPrint (\r
995 mPrivate->PortString,\r
996 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
997 L"%s%d",\r
998 MacString,\r
999 (UINTN) AttemptTmp->AttemptConfigIndex\r
1000 );\r
1001\r
1002 gRT->SetVariable (\r
1003 mPrivate->PortString,\r
1004 &gEfiIScsiInitiatorNameProtocolGuid,\r
1005 ISCSI_CONFIG_VAR_ATTR,\r
1006 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),\r
1007 AttemptTmp\r
1008 );\r
1009\r
1010 continue;\r
1011 }\r
1012 } else if (AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp && !AttemptTmp->ValidPath) {\r
1013 //\r
1014 // Get DHCP information for already added, but failed, attempt.\r
1015 //\r
1016 AttemptTmp->DhcpSuccess = FALSE;\r
1017 if (!mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP4)) {\r
1018 Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);\r
1019 if (!EFI_ERROR (Status)) {\r
1020 AttemptTmp->DhcpSuccess = TRUE;\r
1021 }\r
1022 } else if (mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP6)) {\r
1023 Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);\r
1024 if (!EFI_ERROR (Status)) {\r
1025 AttemptTmp->DhcpSuccess = TRUE;\r
1026 }\r
1027 }\r
1028\r
1029 //\r
1030 // Refresh the state of this attempt to NVR.\r
1031 //\r
1032 AsciiStrToUnicodeStr (AttemptTmp->MacString, MacString);\r
1033 UnicodeSPrint (\r
1034 mPrivate->PortString,\r
1035 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
1036 L"%s%d",\r
1037 MacString,\r
1038 (UINTN) AttemptTmp->AttemptConfigIndex\r
1039 );\r
1040\r
1041 gRT->SetVariable (\r
1042 mPrivate->PortString,\r
1043 &gEfiIScsiInitiatorNameProtocolGuid,\r
1044 ISCSI_CONFIG_VAR_ATTR,\r
1045 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),\r
1046 AttemptTmp\r
1047 );\r
1048\r
1049 continue;\r
1050\r
1051 } else {\r
1052 continue;\r
1053 }\r
1054 }\r
1055\r
1056 //\r
1057 // This attempt does not exist in AttemptConfig. Try to add a new one.\r
1058 //\r
1059\r
1060 NicInfo = IScsiGetNicInfoByIndex (mPrivate->CurrentNic);\r
1061 ASSERT (NicInfo != NULL);\r
1062 IScsiMacAddrToStr (&NicInfo->PermanentAddress, NicInfo->HwAddressSize, NicInfo->VlanId, MacString);\r
1063 UnicodeSPrint (\r
1064 mPrivate->PortString,\r
1065 (UINTN) 128,\r
1066 L"%s%d",\r
1067 MacString,\r
1068 (UINTN) AttemptConfigOrder[Index]\r
1069 );\r
1070\r
1071 AttemptConfigData = (ISCSI_ATTEMPT_CONFIG_NVDATA *) GetVariable (\r
1072 mPrivate->PortString,\r
1073 &gEfiIScsiInitiatorNameProtocolGuid\r
1074 );\r
1075\r
1076 if (AttemptConfigData == NULL) {\r
1077 continue;\r
1078 }\r
1079\r
1080 ASSERT (AttemptConfigOrder[Index] == AttemptConfigData->AttemptConfigIndex);\r
1081\r
1082 AttemptConfigData->NicIndex = NicInfo->NicIndex;\r
1083 AttemptConfigData->DhcpSuccess = FALSE;\r
1084 AttemptConfigData->ValidiBFTPath = (BOOLEAN) (mPrivate->EnableMpio ? TRUE : FALSE);\r
1085 AttemptConfigData->ValidPath = FALSE;\r
1086\r
1087 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {\r
1088 AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp = TRUE;\r
1089 AttemptConfigData->SessionConfigData.TargetInfoFromDhcp = TRUE;\r
1090\r
1091 AttemptConfigData->AutoConfigureMode =\r
1092 (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);\r
1093 }\r
1094 \r
1095 //\r
1096 // Get some information from dhcp server.\r
1097 //\r
1098 if (AttemptConfigData->SessionConfigData.Enabled != ISCSI_DISABLED &&\r
1099 AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp) {\r
1100\r
1101 if (!mPrivate->Ipv6Flag &&\r
1102 (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4 ||\r
1103 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4)) {\r
1104 Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptConfigData);\r
1105 if (!EFI_ERROR (Status)) {\r
1106 AttemptConfigData->DhcpSuccess = TRUE;\r
1107 }\r
1108 } else if (mPrivate->Ipv6Flag &&\r
1109 (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6 ||\r
1110 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6)) {\r
1111 Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptConfigData);\r
1112 if (!EFI_ERROR (Status)) {\r
1113 AttemptConfigData->DhcpSuccess = TRUE;\r
1114 }\r
1115 }\r
1116\r
1117 //\r
1118 // Refresh the state of this attempt to NVR.\r
1119 //\r
1120 AsciiStrToUnicodeStr (AttemptConfigData->MacString, MacString);\r
1121 UnicodeSPrint (\r
1122 mPrivate->PortString,\r
1123 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
1124 L"%s%d",\r
1125 MacString,\r
1126 (UINTN) AttemptConfigData->AttemptConfigIndex\r
1127 );\r
1128\r
1129 gRT->SetVariable (\r
1130 mPrivate->PortString,\r
1131 &gEfiIScsiInitiatorNameProtocolGuid,\r
1132 ISCSI_CONFIG_VAR_ATTR,\r
1133 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),\r
1134 AttemptConfigData\r
1135 );\r
1136 }\r
1137\r
1138 //\r
1139 // Update Attempt Help Info.\r
1140 //\r
1141\r
1142 if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_DISABLED) {\r
1143 UnicodeSPrint (IScsiMode, 64, L"Disabled");\r
1144 } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {\r
1145 UnicodeSPrint (IScsiMode, 64, L"Enabled");\r
1146 } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {\r
1147 UnicodeSPrint (IScsiMode, 64, L"Enabled for MPIO");\r
1148 }\r
1149\r
1150 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4) {\r
1151 UnicodeSPrint (IpMode, 64, L"IP4");\r
1152 } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6) {\r
1153 UnicodeSPrint (IpMode, 64, L"IP6");\r
1154 } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {\r
1155 UnicodeSPrint (IpMode, 64, L"Autoconfigure");\r
1156 }\r
1157\r
1158 UnicodeSPrint (\r
1159 mPrivate->PortString,\r
1160 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
1161 L"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s",\r
1162 MacString,\r
1163 NicInfo->BusNumber,\r
1164 NicInfo->DeviceNumber,\r
1165 NicInfo->FunctionNumber,\r
1166 IScsiMode,\r
1167 IpMode\r
1168 );\r
1169\r
1170 AttemptConfigData->AttemptTitleHelpToken = HiiSetString (\r
1171 mCallbackInfo->RegisteredHandle,\r
1172 0,\r
1173 mPrivate->PortString,\r
1174 NULL\r
1175 );\r
1176 ASSERT (AttemptConfigData->AttemptTitleHelpToken != 0);\r
1177\r
1178 //\r
1179 // Record the attempt in global link list.\r
1180 //\r
1181 InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);\r
1182 mPrivate->AttemptCount++;\r
1183\r
1184 if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {\r
1185 mPrivate->MpioCount++;\r
1186 mPrivate->EnableMpio = TRUE;\r
1187\r
1188 if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB) {\r
1189 mPrivate->Krb5MpioCount++;\r
1190 }\r
1191 } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {\r
1192 mPrivate->SinglePathCount++;\r
1193 }\r
1194 }\r
1195\r
1196 //\r
1197 // Reorder the AttemptConfig by the configured order.\r
1198 //\r
1199 for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {\r
1200 AttemptConfigData = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]);\r
1201 if (AttemptConfigData == NULL) {\r
1202 continue;\r
1203 }\r
1204\r
1205 RemoveEntryList (&AttemptConfigData->Link);\r
1206 InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);\r
1207 }\r
1208\r
1209 //\r
1210 // Update the Main Form.\r
1211 //\r
1212 IScsiConfigUpdateAttempt ();\r
1213\r
1214 FreePool (AttemptConfigOrder);\r
1215\r
1216 //\r
1217 // There should be at least one attempt configuration.\r
1218 //\r
1219 if (!mPrivate->EnableMpio) {\r
1220 if (mPrivate->SinglePathCount == 0) {\r
1221 return EFI_NOT_FOUND;\r
1222 }\r
1223 mPrivate->ValidSinglePathCount = mPrivate->SinglePathCount;\r
1224 }\r
1225\r
1226 return EFI_SUCCESS;\r
1227}\r
1228\r
1229\r
1230/**\r
1231 Get the device path of the iSCSI tcp connection and update it.\r
1232\r
1233 @param Session The iSCSI session.\r
1234\r
1235 @return The updated device path.\r
1236 @retval NULL Other errors as indicated.\r
1237\r
1238**/\r
1239EFI_DEVICE_PATH_PROTOCOL *\r
1240IScsiGetTcpConnDevicePath (\r
1241 IN ISCSI_SESSION *Session\r
1242 )\r
1243{\r
1244 ISCSI_CONNECTION *Conn;\r
1245 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1246 EFI_STATUS Status;\r
1247 EFI_DEV_PATH *DPathNode;\r
1248\r
1249 if (Session->State != SESSION_STATE_LOGGED_IN) {\r
1250 return NULL;\r
1251 }\r
1252\r
1253 Conn = NET_LIST_USER_STRUCT_S (\r
1254 Session->Conns.ForwardLink,\r
1255 ISCSI_CONNECTION,\r
1256 Link,\r
1257 ISCSI_CONNECTION_SIGNATURE\r
1258 );\r
1259\r
1260 Status = gBS->HandleProtocol (\r
1261 Conn->TcpIo.Handle,\r
1262 &gEfiDevicePathProtocolGuid,\r
1263 (VOID **) &DevicePath\r
1264 ); \r
1265 if (EFI_ERROR (Status)) {\r
1266 return NULL;\r
1267 }\r
1268 //\r
1269 // Duplicate it.\r
1270 //\r
1271 DevicePath = DuplicateDevicePath (DevicePath);\r
1272 if (DevicePath == NULL) {\r
1273 return NULL;\r
1274 }\r
1275\r
1276 DPathNode = (EFI_DEV_PATH *) DevicePath;\r
1277\r
1278 while (!IsDevicePathEnd (&DPathNode->DevPath)) {\r
1279 if (DevicePathType (&DPathNode->DevPath) == MESSAGING_DEVICE_PATH) {\r
1280 if (!Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv4_DP) {\r
1281 DPathNode->Ipv4.LocalPort = 0;\r
1282 DPathNode->Ipv4.StaticIpAddress = (BOOLEAN) !Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp;\r
1283 break;\r
1284 } else if (Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv6_DP) {\r
1285 DPathNode->Ipv6.LocalPort = 0;\r
1286 DPathNode->Ipv6.StaticIpAddress = (BOOLEAN) !Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp;\r
1287 break;\r
1288 }\r
1289 }\r
1290\r
1291 DPathNode = (EFI_DEV_PATH *) NextDevicePathNode (&DPathNode->DevPath);\r
1292 }\r
1293\r
1294 return DevicePath;\r
1295}\r
1296\r
1297\r
1298/**\r
1299 Abort the session when the transition from BS to RT is initiated.\r
1300\r
1301 @param[in] Event The event signaled.\r
1302 @param[in] Context The iSCSI driver data.\r
1303\r
1304**/\r
1305VOID\r
1306EFIAPI\r
1307IScsiOnExitBootService (\r
1308 IN EFI_EVENT Event,\r
1309 IN VOID *Context\r
1310 )\r
1311{\r
1312 ISCSI_DRIVER_DATA *Private;\r
1313\r
1314 Private = (ISCSI_DRIVER_DATA *) Context;\r
1315 gBS->CloseEvent (Private->ExitBootServiceEvent);\r
1316\r
1317 if (Private->Session != NULL) {\r
1318 IScsiSessionAbort (Private->Session);\r
1319 }\r
1320}\r