]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Universal/Network/IScsiDxe/IScsiConfig.c
Update HiiDataBase to fix the SCT hang issues by the invalid device path.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / IScsiDxe / IScsiConfig.c
... / ...
CommitLineData
1/** @file\r
2 Helper functions for configuring or getting the parameters relating to iSCSI.\r
3\r
4Copyright (c) 2004 - 2008, Intel Corporation.<BR>\r
5All rights reserved. This 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
17EFI_GUID mVendorGuid = ISCSI_CONFIG_GUID;\r
18CHAR16 mVendorStorageName[] = L"ISCSI_CONFIG_IFR_NVDATA";\r
19BOOLEAN mIScsiDeviceListUpdated = FALSE;\r
20UINTN mNumberOfIScsiDevices = 0;\r
21ISCSI_FORM_CALLBACK_INFO *mCallbackInfo = NULL;\r
22\r
23LIST_ENTRY mIScsiConfigFormList = {\r
24 &mIScsiConfigFormList,\r
25 &mIScsiConfigFormList\r
26};\r
27\r
28HII_VENDOR_DEVICE_PATH mIScsiHiiVendorDevicePath = {\r
29 {\r
30 {\r
31 HARDWARE_DEVICE_PATH,\r
32 HW_VENDOR_DP,\r
33 {\r
34 (UINT8) (sizeof (VENDOR_DEVICE_PATH)),\r
35 (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)\r
36 }\r
37 },\r
38 //\r
39 // {49D7B73E-143D-4716-977B-C45F1CB038CC}\r
40 //\r
41 { 0x49d7b73e, 0x143d, 0x4716, { 0x97, 0x7b, 0xc4, 0x5f, 0x1c, 0xb0, 0x38, 0xcc } }\r
42 },\r
43 {\r
44 END_DEVICE_PATH_TYPE,\r
45 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
46 { \r
47 (UINT8) (END_DEVICE_PATH_LENGTH),\r
48 (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)\r
49 }\r
50 }\r
51};\r
52\r
53/**\r
54 Convert the IPv4 address into a dotted string.\r
55\r
56 @param[in] Ip The IPv4 address.\r
57 @param[out] Str The dotted IP string.\r
58**/\r
59VOID\r
60IScsiIpToStr (\r
61 IN EFI_IPv4_ADDRESS *Ip,\r
62 OUT CHAR16 *Str\r
63 )\r
64{\r
65 UnicodeSPrint ( Str, 2 * IP4_STR_MAX_SIZE, L"%d.%d.%d.%d", Ip->Addr[0], Ip->Addr[1], Ip->Addr[2], Ip->Addr[3]);\r
66}\r
67\r
68/**\r
69 Update the list of iSCSI devices the iSCSI driver is controlling.\r
70 \r
71 @retval EFI_SUCCESS The callback successfully handled the action.\r
72 @retval Others Other errors as indicated. \r
73**/\r
74EFI_STATUS\r
75IScsiUpdateDeviceList (\r
76 VOID\r
77 )\r
78{\r
79 EFI_STATUS Status;\r
80 ISCSI_DEVICE_LIST *DeviceList;\r
81 UINTN DataSize;\r
82 UINTN NumHandles;\r
83 EFI_HANDLE *Handles;\r
84 UINTN HandleIndex;\r
85 UINTN Index;\r
86 UINTN LastDeviceIndex;\r
87 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
88 EFI_SIMPLE_NETWORK_MODE *Mode;\r
89 ISCSI_MAC_INFO *CurMacInfo;\r
90 ISCSI_MAC_INFO TempMacInfo;\r
91 CHAR16 MacString[65];\r
92 UINTN DeviceListSize;\r
93\r
94 //\r
95 // Dump all the handles the Simple Network Protocol is installed on.\r
96 //\r
97 Status = gBS->LocateHandleBuffer (\r
98 ByProtocol,\r
99 &gEfiSimpleNetworkProtocolGuid,\r
100 NULL,\r
101 &NumHandles,\r
102 &Handles\r
103 );\r
104 if (EFI_ERROR (Status)) {\r
105 return Status;\r
106 }\r
107\r
108 DataSize = 0;\r
109 Status = gRT->GetVariable (\r
110 L"iSCSIDeviceList",\r
111 &mVendorGuid,\r
112 NULL,\r
113 &DataSize,\r
114 NULL\r
115 );\r
116 if (Status == EFI_BUFFER_TOO_SMALL) {\r
117 DeviceList = (ISCSI_DEVICE_LIST *) AllocatePool (DataSize);\r
118\r
119 gRT->GetVariable (\r
120 L"iSCSIDeviceList",\r
121 &mVendorGuid,\r
122 NULL,\r
123 &DataSize,\r
124 DeviceList\r
125 );\r
126\r
127 LastDeviceIndex = 0;\r
128\r
129 for (HandleIndex = 0; HandleIndex < NumHandles; HandleIndex++) {\r
130 gBS->HandleProtocol (Handles[HandleIndex], &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp);\r
131\r
132 Mode = Snp->Mode;\r
133\r
134 for (Index = LastDeviceIndex; Index < DeviceList->NumDevice; Index++) {\r
135 CurMacInfo = &DeviceList->MacInfo[Index];\r
136 if ((CurMacInfo->Len == Mode->HwAddressSize) &&\r
137 (NET_MAC_EQUAL (&CurMacInfo->Mac, &Mode->PermanentAddress, Mode->HwAddressSize))\r
138 ) {\r
139 //\r
140 // The previous configured NIC is still here.\r
141 //\r
142 if (Index != LastDeviceIndex) {\r
143 //\r
144 // Swap the current MAC address entry with the one indexed by\r
145 // LastDeviceIndex.\r
146 //\r
147 CopyMem (&TempMacInfo, CurMacInfo, sizeof (ISCSI_MAC_INFO));\r
148 CopyMem (CurMacInfo, &DeviceList->MacInfo[LastDeviceIndex], sizeof (ISCSI_MAC_INFO));\r
149 CopyMem (&DeviceList->MacInfo[LastDeviceIndex], &TempMacInfo, sizeof (ISCSI_MAC_INFO));\r
150 }\r
151\r
152 LastDeviceIndex++;\r
153 }\r
154 }\r
155\r
156 if (LastDeviceIndex == DeviceList->NumDevice) {\r
157 break;\r
158 }\r
159 }\r
160\r
161 for (Index = LastDeviceIndex; Index < DeviceList->NumDevice; Index++) {\r
162 //\r
163 // delete the variables\r
164 //\r
165 CurMacInfo = &DeviceList->MacInfo[Index];\r
166 IScsiMacAddrToStr (&CurMacInfo->Mac, CurMacInfo->Len, MacString);\r
167 gRT->SetVariable (MacString, &gEfiIScsiInitiatorNameProtocolGuid, 0, 0, NULL);\r
168 gRT->SetVariable (MacString, &mIScsiCHAPAuthInfoGuid, 0, 0, NULL);\r
169 }\r
170\r
171 gBS->FreePool (DeviceList);\r
172 } else if (Status != EFI_NOT_FOUND) {\r
173 gBS->FreePool (Handles);\r
174 return Status;\r
175 }\r
176 //\r
177 // Construct the new iSCSI device list.\r
178 //\r
179 DeviceListSize = sizeof (ISCSI_DEVICE_LIST) + (NumHandles - 1) * sizeof (ISCSI_MAC_INFO);\r
180 DeviceList = (ISCSI_DEVICE_LIST *) AllocatePool (DeviceListSize);\r
181 DeviceList->NumDevice = (UINT8) NumHandles;\r
182\r
183 for (Index = 0; Index < NumHandles; Index++) {\r
184 gBS->HandleProtocol (Handles[Index], &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp);\r
185 Mode = Snp->Mode;\r
186\r
187 CurMacInfo = &DeviceList->MacInfo[Index];\r
188 CopyMem (&CurMacInfo->Mac, &Mode->PermanentAddress, Mode->HwAddressSize);\r
189 CurMacInfo->Len = (UINT8) Mode->HwAddressSize;\r
190 }\r
191\r
192 gRT->SetVariable (\r
193 L"iSCSIDeviceList",\r
194 &mVendorGuid,\r
195 ISCSI_CONFIG_VAR_ATTR,\r
196 DeviceListSize,\r
197 DeviceList\r
198 );\r
199\r
200 gBS->FreePool (DeviceList);\r
201 gBS->FreePool (Handles);\r
202\r
203 return Status;\r
204}\r
205\r
206/**\r
207 Get the iSCSI configuration form entry by the index of the goto opcode actived.\r
208\r
209 @param[in] Index The 0-based index of the goto opcode actived.\r
210\r
211 @return The iSCSI configuration form entry found.\r
212**/\r
213ISCSI_CONFIG_FORM_ENTRY *\r
214IScsiGetConfigFormEntryByIndex (\r
215 IN UINT32 Index\r
216 )\r
217{\r
218 UINT32 CurrentIndex;\r
219 LIST_ENTRY *Entry;\r
220 ISCSI_CONFIG_FORM_ENTRY *ConfigFormEntry;\r
221\r
222 CurrentIndex = 0;\r
223 ConfigFormEntry = NULL;\r
224\r
225 NET_LIST_FOR_EACH (Entry, &mIScsiConfigFormList) {\r
226 if (CurrentIndex == Index) {\r
227 ConfigFormEntry = NET_LIST_USER_STRUCT (Entry, ISCSI_CONFIG_FORM_ENTRY, Link);\r
228 break;\r
229 }\r
230\r
231 CurrentIndex++;\r
232 }\r
233\r
234 return ConfigFormEntry;\r
235}\r
236\r
237/**\r
238 Convert the iSCSI configuration data into the IFR data.\r
239\r
240 @param[in] ConfigFormEntry The iSCSI configuration form entry.\r
241 @param[out] IfrNvData The IFR nv data.\r
242**/\r
243VOID\r
244IScsiConvertDeviceConfigDataToIfrNvData (\r
245 IN ISCSI_CONFIG_FORM_ENTRY *ConfigFormEntry,\r
246 OUT ISCSI_CONFIG_IFR_NVDATA *IfrNvData\r
247 )\r
248{\r
249 ISCSI_SESSION_CONFIG_NVDATA *SessionConfigData;\r
250 ISCSI_CHAP_AUTH_CONFIG_NVDATA *AuthConfigData;\r
251\r
252 //\r
253 // Normal session configuration parameters.\r
254 //\r
255 SessionConfigData = &ConfigFormEntry->SessionConfigData;\r
256 IfrNvData->Enabled = SessionConfigData->Enabled;\r
257\r
258 IfrNvData->InitiatorInfoFromDhcp = SessionConfigData->InitiatorInfoFromDhcp;\r
259 IfrNvData->TargetInfoFromDhcp = SessionConfigData->TargetInfoFromDhcp;\r
260 IfrNvData->TargetPort = SessionConfigData->TargetPort;\r
261\r
262 IScsiIpToStr (&SessionConfigData->LocalIp, IfrNvData->LocalIp);\r
263 IScsiIpToStr (&SessionConfigData->SubnetMask, IfrNvData->SubnetMask);\r
264 IScsiIpToStr (&SessionConfigData->Gateway, IfrNvData->Gateway);\r
265 IScsiIpToStr (&SessionConfigData->TargetIp, IfrNvData->TargetIp);\r
266\r
267 IScsiAsciiStrToUnicodeStr (SessionConfigData->TargetName, IfrNvData->TargetName);\r
268\r
269 IScsiLunToUnicodeStr (SessionConfigData->BootLun, IfrNvData->BootLun);\r
270\r
271 //\r
272 // CHAP authentication parameters.\r
273 //\r
274 AuthConfigData = &ConfigFormEntry->AuthConfigData;\r
275\r
276 IfrNvData->CHAPType = AuthConfigData->CHAPType;\r
277\r
278 IScsiAsciiStrToUnicodeStr (AuthConfigData->CHAPName, IfrNvData->CHAPName);\r
279 IScsiAsciiStrToUnicodeStr (AuthConfigData->CHAPSecret, IfrNvData->CHAPSecret);\r
280 IScsiAsciiStrToUnicodeStr (AuthConfigData->ReverseCHAPName, IfrNvData->ReverseCHAPName);\r
281 IScsiAsciiStrToUnicodeStr (AuthConfigData->ReverseCHAPSecret, IfrNvData->ReverseCHAPSecret);\r
282}\r
283\r
284/**\r
285 This function allows the caller to request the current\r
286 configuration for one or more named elements. The resulting\r
287 string is in <ConfigAltResp> format. Any and all alternative\r
288 configuration strings shall also be appended to the end of the\r
289 current configuration string. If they are, they must appear\r
290 after the current configuration. They must contain the same\r
291 routing (GUID, NAME, PATH) as the current configuration string.\r
292 They must have an additional description indicating the type of\r
293 alternative configuration the string represents,\r
294 "ALTCFG=<StringToken>". That <StringToken> (when\r
295 converted from Hex UNICODE to binary) is a reference to a\r
296 string in the associated string pack.\r
297\r
298 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
299 @param[in] Request A null-terminated Unicode string in\r
300 <ConfigRequest> format. Note that this\r
301 includes the routing information as well as\r
302 the configurable name / value pairs. It is\r
303 invalid for this string to be in\r
304 <MultiConfigRequest> format.\r
305 @param[out] Progress On return, points to a character in the\r
306 Request string. Points to the string's null\r
307 terminator if request was successful. Points\r
308 to the most recent "&" before the first\r
309 failing name / value pair (or the beginning\r
310 of the string if the failure is in the first\r
311 name / value pair) if the request was not\r
312 successful.\r
313 @param[out] Results A null-terminated Unicode string in\r
314 <ConfigAltResp> format which has all values\r
315 filled in for the names in the Request string.\r
316 String to be allocated by the called function.\r
317\r
318 @retval EFI_SUCCESS The Results string is filled with the\r
319 values corresponding to all requested\r
320 names.\r
321 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the\r
322 parts of the results that must be\r
323 stored awaiting possible future\r
324 protocols.\r
325 @retval EFI_INVALID_PARAMETER For example, passing in a NULL\r
326 for the Request parameter\r
327 would result in this type of\r
328 error. In this case, the\r
329 Progress parameter would be\r
330 set to NULL. \r
331 @retval EFI_NOT_FOUND Routing data doesn't match any\r
332 known driver. Progress set to the\r
333 first character in the routing header.\r
334 Note: There is no requirement that the\r
335 driver validate the routing data. It\r
336 must skip the <ConfigHdr> in order to\r
337 process the names.\r
338 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set\r
339 to most recent & before the\r
340 error or the beginning of the\r
341 string.\r
342 @retval EFI_INVALID_PARAMETER Unknown name. Progress points\r
343 to the & before the name in\r
344 question.Currently not implemented.\r
345**/\r
346EFI_STATUS\r
347EFIAPI\r
348IScsiFormExtractConfig (\r
349 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
350 IN CONST EFI_STRING Request,\r
351 OUT EFI_STRING *Progress,\r
352 OUT EFI_STRING *Results\r
353 )\r
354{\r
355 EFI_STATUS Status;\r
356 CHAR8 InitiatorName[ISCSI_NAME_IFR_MAX_SIZE];\r
357 UINTN BufferSize;\r
358 ISCSI_CONFIG_IFR_NVDATA *IfrNvData;\r
359 ISCSI_FORM_CALLBACK_INFO *Private;\r
360 EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;\r
361\r
362 if (Request == NULL || Progress == NULL || Results == NULL) {\r
363 return EFI_INVALID_PARAMETER;\r
364 }\r
365 *Progress = Request;\r
366\r
367 if (!mIScsiDeviceListUpdated) {\r
368 //\r
369 // Update the device list.\r
370 //\r
371 IScsiUpdateDeviceList ();\r
372 mIScsiDeviceListUpdated = TRUE;\r
373 }\r
374\r
375 Private = ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This);\r
376 IfrNvData = AllocateZeroPool (sizeof (ISCSI_CONFIG_IFR_NVDATA));\r
377 ASSERT (IfrNvData != NULL);\r
378 if (Private->Current != NULL) {\r
379 IScsiConvertDeviceConfigDataToIfrNvData (Private->Current, IfrNvData);\r
380 }\r
381\r
382 BufferSize = ISCSI_NAME_IFR_MAX_SIZE;\r
383 Status = gIScsiInitiatorName.Get (&gIScsiInitiatorName, &BufferSize, InitiatorName);\r
384 if (EFI_ERROR (Status)) {\r
385 IfrNvData->InitiatorName[0] = L'\0';\r
386 } else {\r
387 IScsiAsciiStrToUnicodeStr (InitiatorName, IfrNvData->InitiatorName);\r
388 }\r
389\r
390 //\r
391 // Convert buffer data to <ConfigResp> by helper function BlockToConfig()\r
392 //\r
393 HiiConfigRouting = Private->ConfigRouting;\r
394 BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA);\r
395 Status = HiiConfigRouting->BlockToConfig (\r
396 HiiConfigRouting,\r
397 Request,\r
398 (UINT8 *) IfrNvData,\r
399 BufferSize,\r
400 Results,\r
401 Progress\r
402 );\r
403 gBS->FreePool (IfrNvData);\r
404 return Status;\r
405}\r
406\r
407/**\r
408 This function applies changes in a driver's configuration.\r
409 Input is a Configuration, which has the routing data for this\r
410 driver followed by name / value configuration pairs. The driver\r
411 must apply those pairs to its configurable storage. If the\r
412 driver's configuration is stored in a linear block of data\r
413 and the driver's name / value pairs are in <BlockConfig>\r
414 format, it may use the ConfigToBlock helper function (above) to\r
415 simplify the job. Currently not implemented.\r
416\r
417 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
418 @param[in] Configuration A null-terminated Unicode string in\r
419 <ConfigString> format. \r
420 @param[out] Progress A pointer to a string filled in with the\r
421 offset of the most recent '&' before the\r
422 first failing name / value pair (or the\r
423 beginn ing of the string if the failure\r
424 is in the first name / value pair) or\r
425 the terminating NULL if all was\r
426 successful.\r
427\r
428 @retval EFI_SUCCESS The results have been distributed or are\r
429 awaiting distribution. \r
430 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the\r
431 parts of the results that must be\r
432 stored awaiting possible future\r
433 protocols.\r
434 @retval EFI_INVALID_PARAMETERS Passing in a NULL for the\r
435 Results parameter would result\r
436 in this type of error.\r
437 @retval EFI_NOT_FOUND Target for the specified routing data\r
438 was not found.\r
439**/\r
440EFI_STATUS\r
441EFIAPI\r
442IScsiFormRouteConfig (\r
443 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
444 IN CONST EFI_STRING Configuration,\r
445 OUT EFI_STRING *Progress\r
446 )\r
447{\r
448 if (Configuration == NULL || Progress == NULL) {\r
449 return EFI_INVALID_PARAMETER;\r
450 }\r
451\r
452 //\r
453 // Check routing data in <ConfigHdr>.\r
454 // Note: if only one Storage is used, then this checking could be skipped.\r
455 //\r
456 if (!HiiIsConfigHdrMatch (Configuration, &mVendorGuid, mVendorStorageName)) {\r
457 *Progress = Configuration;\r
458 return EFI_NOT_FOUND;\r
459 }\r
460\r
461 *Progress = Configuration + StrLen (Configuration);\r
462 return EFI_SUCCESS;\r
463}\r
464\r
465/**\r
466 This function is called to provide results data to the driver.\r
467 This data consists of a unique key that is used to identify\r
468 which data is either being passed back or being asked for.\r
469\r
470 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
471 @param[in] Action Specifies the type of action taken by the browser.\r
472 @param[in] QuestionId A unique value which is sent to the original\r
473 exporting driver so that it can identify the type\r
474 of data to expect. The format of the data tends to \r
475 vary based on the opcode that enerated the callback.\r
476 @param[in] Type The type of value for the question.\r
477 @param[in] Value A pointer to the data being sent to the original\r
478 exporting driver.\r
479 @param[out] ActionRequest On return, points to the action requested by the\r
480 callback function.\r
481\r
482 @retval EFI_SUCCESS The callback successfully handled the action.\r
483 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the\r
484 variable and its data.\r
485 @retval EFI_DEVICE_ERROR The variable could not be saved.\r
486 @retval EFI_UNSUPPORTED The specified Action is not supported by the\r
487 callback.Currently not implemented.\r
488 @retval EFI_INVALID_PARAMETERS Passing in wrong parameter. \r
489 @retval Others Other errors as indicated. \r
490**/\r
491EFI_STATUS\r
492EFIAPI\r
493IScsiFormCallback (\r
494 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
495 IN EFI_BROWSER_ACTION Action,\r
496 IN EFI_QUESTION_ID QuestionId,\r
497 IN UINT8 Type,\r
498 IN EFI_IFR_TYPE_VALUE *Value,\r
499 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest\r
500 )\r
501{\r
502 ISCSI_FORM_CALLBACK_INFO *Private;\r
503 UINTN BufferSize;\r
504 CHAR8 IScsiName[ISCSI_NAME_IFR_MAX_SIZE];\r
505 CHAR16 PortString[128];\r
506 CHAR8 Ip4String[IP4_STR_MAX_SIZE];\r
507 CHAR8 LunString[ISCSI_LUN_STR_MAX_LEN];\r
508 UINT64 Lun;\r
509 EFI_STRING_ID DeviceFormTitleToken;\r
510 ISCSI_CONFIG_IFR_NVDATA *IfrNvData;\r
511 ISCSI_CONFIG_FORM_ENTRY *ConfigFormEntry;\r
512 EFI_IP_ADDRESS HostIp;\r
513 EFI_IP_ADDRESS SubnetMask;\r
514 EFI_IP_ADDRESS Gateway;\r
515 EFI_STATUS Status;\r
516 EFI_INPUT_KEY Key;\r
517\r
518 Private = ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This);\r
519\r
520 //\r
521 // Retrive uncommitted data from Browser\r
522 //\r
523 IfrNvData = AllocateZeroPool (sizeof (ISCSI_CONFIG_IFR_NVDATA));\r
524 ASSERT (IfrNvData != NULL);\r
525 if (!HiiGetBrowserData (&mVendorGuid, mVendorStorageName, sizeof (ISCSI_CONFIG_IFR_NVDATA), (UINT8 *) IfrNvData)) {\r
526 FreePool (IfrNvData);\r
527 return EFI_NOT_FOUND;\r
528 }\r
529 \r
530 Status = EFI_SUCCESS;\r
531\r
532 switch (QuestionId) {\r
533 case KEY_INITIATOR_NAME:\r
534 IScsiUnicodeStrToAsciiStr (IfrNvData->InitiatorName, IScsiName);\r
535 BufferSize = AsciiStrLen (IScsiName) + 1;\r
536\r
537 Status = gIScsiInitiatorName.Set (&gIScsiInitiatorName, &BufferSize, IScsiName);\r
538 if (EFI_ERROR (Status)) {\r
539 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid iSCSI Name!", NULL);\r
540 }\r
541\r
542 break;\r
543\r
544 case KEY_LOCAL_IP:\r
545 IScsiUnicodeStrToAsciiStr (IfrNvData->LocalIp, Ip4String);\r
546 Status = IScsiAsciiStrToIp (Ip4String, &HostIp.v4);\r
547 if (EFI_ERROR (Status) || !Ip4IsUnicast (NTOHL (HostIp.Addr[0]), 0)) {\r
548 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid IP address!", NULL);\r
549 Status = EFI_INVALID_PARAMETER;\r
550 } else {\r
551 CopyMem (&Private->Current->SessionConfigData.LocalIp, &HostIp.v4, sizeof (HostIp.v4));\r
552 }\r
553\r
554 break;\r
555\r
556 case KEY_SUBNET_MASK:\r
557 IScsiUnicodeStrToAsciiStr (IfrNvData->SubnetMask, Ip4String);\r
558 Status = IScsiAsciiStrToIp (Ip4String, &SubnetMask.v4);\r
559 if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (IScsiGetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {\r
560 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Subnet Mask!", NULL);\r
561 Status = EFI_INVALID_PARAMETER;\r
562 } else {\r
563 CopyMem (&Private->Current->SessionConfigData.SubnetMask, &SubnetMask.v4, sizeof (SubnetMask.v4));\r
564 }\r
565\r
566 break;\r
567\r
568 case KEY_GATE_WAY:\r
569 IScsiUnicodeStrToAsciiStr (IfrNvData->Gateway, Ip4String);\r
570 Status = IScsiAsciiStrToIp (Ip4String, &Gateway.v4);\r
571 if (EFI_ERROR (Status) || ((Gateway.Addr[0] != 0) && !Ip4IsUnicast (NTOHL (Gateway.Addr[0]), 0))) {\r
572 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Gateway!", NULL);\r
573 Status = EFI_INVALID_PARAMETER;\r
574 } else {\r
575 CopyMem (&Private->Current->SessionConfigData.Gateway, &Gateway.v4, sizeof (Gateway.v4));\r
576 }\r
577\r
578 break;\r
579\r
580 case KEY_TARGET_IP:\r
581 IScsiUnicodeStrToAsciiStr (IfrNvData->TargetIp, Ip4String);\r
582 Status = IScsiAsciiStrToIp (Ip4String, &HostIp.v4);\r
583 if (EFI_ERROR (Status) || !Ip4IsUnicast (NTOHL (HostIp.Addr[0]), 0)) {\r
584 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid IP address!", NULL);\r
585 Status = EFI_INVALID_PARAMETER;\r
586 } else {\r
587 CopyMem (&Private->Current->SessionConfigData.TargetIp, &HostIp.v4, sizeof (HostIp.v4));\r
588 }\r
589\r
590 break;\r
591\r
592 case KEY_TARGET_NAME:\r
593 IScsiUnicodeStrToAsciiStr (IfrNvData->TargetName, IScsiName);\r
594 Status = IScsiNormalizeName (IScsiName, AsciiStrLen (IScsiName));\r
595 if (EFI_ERROR (Status)) {\r
596 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid iSCSI Name!", NULL);\r
597 } else {\r
598 AsciiStrCpy (Private->Current->SessionConfigData.TargetName, IScsiName);\r
599 }\r
600\r
601 break;\r
602\r
603 case KEY_DHCP_ENABLE:\r
604 if (IfrNvData->InitiatorInfoFromDhcp == 0) {\r
605 IfrNvData->TargetInfoFromDhcp = 0;\r
606 }\r
607\r
608 break;\r
609\r
610 case KEY_BOOT_LUN:\r
611 IScsiUnicodeStrToAsciiStr (IfrNvData->BootLun, LunString);\r
612 Status = IScsiAsciiStrToLun (LunString, (UINT8 *) &Lun);\r
613 if (EFI_ERROR (Status)) {\r
614 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid LUN string!", NULL);\r
615 } else {\r
616 CopyMem (Private->Current->SessionConfigData.BootLun, &Lun, sizeof (Lun));\r
617 }\r
618\r
619 break;\r
620\r
621 case KEY_CHAP_NAME:\r
622 IScsiUnicodeStrToAsciiStr (IfrNvData->CHAPName, Private->Current->AuthConfigData.CHAPName);\r
623 break;\r
624\r
625 case KEY_CHAP_SECRET:\r
626 IScsiUnicodeStrToAsciiStr (IfrNvData->CHAPSecret, Private->Current->AuthConfigData.CHAPSecret);\r
627 break;\r
628\r
629 case KEY_REVERSE_CHAP_NAME:\r
630 IScsiUnicodeStrToAsciiStr (IfrNvData->ReverseCHAPName, Private->Current->AuthConfigData.ReverseCHAPName);\r
631 break;\r
632\r
633 case KEY_REVERSE_CHAP_SECRET:\r
634 IScsiUnicodeStrToAsciiStr (IfrNvData->ReverseCHAPSecret, Private->Current->AuthConfigData.ReverseCHAPSecret);\r
635 break;\r
636\r
637 case KEY_SAVE_CHANGES:\r
638 //\r
639 // First, update those fields which don't have INTERACTIVE set.\r
640 //\r
641 Private->Current->SessionConfigData.Enabled = IfrNvData->Enabled;\r
642 Private->Current->SessionConfigData.InitiatorInfoFromDhcp = IfrNvData->InitiatorInfoFromDhcp;\r
643 Private->Current->SessionConfigData.TargetPort = IfrNvData->TargetPort;\r
644 if (Private->Current->SessionConfigData.TargetPort == 0) {\r
645 Private->Current->SessionConfigData.TargetPort = ISCSI_WELL_KNOWN_PORT;\r
646 }\r
647\r
648 Private->Current->SessionConfigData.TargetInfoFromDhcp = IfrNvData->TargetInfoFromDhcp;\r
649 Private->Current->AuthConfigData.CHAPType = IfrNvData->CHAPType;\r
650\r
651 //\r
652 // Only do full parameter validation if iSCSI is enabled on this device.\r
653 //\r
654 if (Private->Current->SessionConfigData.Enabled) {\r
655 //\r
656 // Validate the address configuration of the Initiator if DHCP isn't\r
657 // deployed.\r
658 //\r
659 if (!Private->Current->SessionConfigData.InitiatorInfoFromDhcp) {\r
660 CopyMem (&HostIp.v4, &Private->Current->SessionConfigData.LocalIp, sizeof (HostIp.v4));\r
661 CopyMem (&SubnetMask.v4, &Private->Current->SessionConfigData.SubnetMask, sizeof (SubnetMask.v4));\r
662 CopyMem (&Gateway.v4, &Private->Current->SessionConfigData.Gateway, sizeof (Gateway.v4));\r
663\r
664 if ((Gateway.Addr[0] != 0)) {\r
665 if (SubnetMask.Addr[0] == 0) {\r
666 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Gateway address is set but subnet mask is zero.", NULL);\r
667 Status = EFI_INVALID_PARAMETER;\r
668 break;\r
669 } else if (!IP4_NET_EQUAL (HostIp.Addr[0], Gateway.Addr[0], SubnetMask.Addr[0])) {\r
670 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Local IP and Gateway are not in the same subnet.", NULL);\r
671 Status = EFI_INVALID_PARAMETER;\r
672 break;\r
673 }\r
674 }\r
675 }\r
676 //\r
677 // Validate target configuration if DHCP isn't deployed.\r
678 //\r
679 if (!Private->Current->SessionConfigData.TargetInfoFromDhcp) {\r
680 CopyMem (&HostIp.v4, &Private->Current->SessionConfigData.TargetIp, sizeof (HostIp.v4));\r
681 if (!Ip4IsUnicast (NTOHL (HostIp.Addr[0]), 0)) {\r
682 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Target IP is invalid!", NULL);\r
683 Status = EFI_INVALID_PARAMETER;\r
684 break;\r
685 }\r
686 }\r
687\r
688 if (IfrNvData->CHAPType != ISCSI_CHAP_NONE) {\r
689 if ((IfrNvData->CHAPName[0] == '\0') || (IfrNvData->CHAPSecret[0] == '\0')) {\r
690 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"CHAP Name or CHAP Secret is invalid!", NULL);\r
691 Status = EFI_INVALID_PARAMETER;\r
692 break;\r
693 }\r
694\r
695 if ((IfrNvData->CHAPType == ISCSI_CHAP_MUTUAL) &&\r
696 ((IfrNvData->ReverseCHAPName[0] == '\0') || (IfrNvData->ReverseCHAPSecret[0] == '\0'))\r
697 ) {\r
698 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Reverse CHAP Name or Reverse CHAP Secret is invalid!", NULL);\r
699 Status = EFI_INVALID_PARAMETER;\r
700 break;\r
701 }\r
702 }\r
703 }\r
704\r
705 BufferSize = sizeof (Private->Current->SessionConfigData);\r
706 gRT->SetVariable (\r
707 Private->Current->MacString,\r
708 &gEfiIScsiInitiatorNameProtocolGuid,\r
709 ISCSI_CONFIG_VAR_ATTR,\r
710 BufferSize,\r
711 &Private->Current->SessionConfigData\r
712 );\r
713\r
714 BufferSize = sizeof (Private->Current->AuthConfigData);\r
715 gRT->SetVariable (\r
716 Private->Current->MacString,\r
717 &mIScsiCHAPAuthInfoGuid,\r
718 ISCSI_CONFIG_VAR_ATTR,\r
719 BufferSize,\r
720 &Private->Current->AuthConfigData\r
721 );\r
722 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
723 break;\r
724\r
725 default:\r
726 if ((QuestionId >= KEY_DEVICE_ENTRY_BASE) && (QuestionId < (mNumberOfIScsiDevices + KEY_DEVICE_ENTRY_BASE))) {\r
727 //\r
728 // In case goto the device configuration form, update the device form title.\r
729 //\r
730 ConfigFormEntry = IScsiGetConfigFormEntryByIndex ((UINT32) (QuestionId - KEY_DEVICE_ENTRY_BASE));\r
731 ASSERT (ConfigFormEntry != NULL);\r
732\r
733 UnicodeSPrint (PortString, (UINTN) 128, L"Port %s", ConfigFormEntry->MacString);\r
734 DeviceFormTitleToken = (EFI_STRING_ID) STR_ISCSI_DEVICE_FORM_TITLE;\r
735 HiiSetString (Private->RegisteredHandle, DeviceFormTitleToken, PortString, NULL);\r
736\r
737 IScsiConvertDeviceConfigDataToIfrNvData (ConfigFormEntry, IfrNvData);\r
738\r
739 Private->Current = ConfigFormEntry;\r
740 }\r
741\r
742 break;\r
743 }\r
744\r
745 if (!EFI_ERROR (Status)) {\r
746 //\r
747 // Pass changed uncommitted data back to Form Browser\r
748 //\r
749 HiiSetBrowserData (&mVendorGuid, mVendorStorageName, sizeof (ISCSI_CONFIG_IFR_NVDATA), (UINT8 *) IfrNvData, NULL);\r
750 }\r
751\r
752 FreePool (IfrNvData);\r
753 return Status;\r
754}\r
755\r
756/**\r
757 Updates the iSCSI configuration form to add/delete an entry for the iSCSI\r
758 device specified by the Controller.\r
759\r
760 @param[in] DriverBindingHandle The driverbinding handle.\r
761 @param[in] Controller The controller handle of the iSCSI device.\r
762 @param[in] AddForm Whether to add or delete a form entry.\r
763\r
764 @retval EFI_SUCCESS The iSCSI configuration form is updated.\r
765 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
766 @retval Others Other errors as indicated.\r
767**/\r
768EFI_STATUS\r
769IScsiConfigUpdateForm (\r
770 IN EFI_HANDLE DriverBindingHandle,\r
771 IN EFI_HANDLE Controller,\r
772 IN BOOLEAN AddForm\r
773 )\r
774{\r
775 LIST_ENTRY *Entry;\r
776 ISCSI_CONFIG_FORM_ENTRY *ConfigFormEntry;\r
777 BOOLEAN EntryExisted;\r
778 EFI_STATUS Status;\r
779 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
780 CHAR16 PortString[128];\r
781 UINT16 FormIndex;\r
782 UINTN BufferSize;\r
783 VOID *StartOpCodeHandle;\r
784 VOID *EndOpCodeHandle;\r
785 EFI_IFR_GUID_LABEL *StartLabel;\r
786 EFI_IFR_GUID_LABEL *EndLabel;\r
787\r
788 ConfigFormEntry = NULL;\r
789 EntryExisted = FALSE;\r
790\r
791 NET_LIST_FOR_EACH (Entry, &mIScsiConfigFormList) {\r
792 ConfigFormEntry = NET_LIST_USER_STRUCT (Entry, ISCSI_CONFIG_FORM_ENTRY, Link);\r
793\r
794 if (ConfigFormEntry->Controller == Controller) {\r
795 EntryExisted = TRUE;\r
796 break;\r
797 }\r
798 }\r
799\r
800 if (AddForm) {\r
801 if (EntryExisted) {\r
802 return EFI_SUCCESS;\r
803 } else {\r
804 //\r
805 // Add a new form.\r
806 //\r
807 ConfigFormEntry = (ISCSI_CONFIG_FORM_ENTRY *) AllocateZeroPool (sizeof (ISCSI_CONFIG_FORM_ENTRY));\r
808 if (ConfigFormEntry == NULL) {\r
809 return EFI_OUT_OF_RESOURCES;\r
810 }\r
811\r
812 InitializeListHead (&ConfigFormEntry->Link);\r
813 ConfigFormEntry->Controller = Controller;\r
814\r
815 //\r
816 // Get the simple network protocol and convert the MAC address into\r
817 // the formatted string.\r
818 //\r
819 Status = gBS->HandleProtocol (\r
820 Controller,\r
821 &gEfiSimpleNetworkProtocolGuid,\r
822 (VOID **)&Snp\r
823 );\r
824 ASSERT (Status == EFI_SUCCESS);\r
825\r
826 IScsiMacAddrToStr (&Snp->Mode->PermanentAddress, Snp->Mode->HwAddressSize, ConfigFormEntry->MacString);\r
827\r
828 //\r
829 // Get the normal session configuration data.\r
830 //\r
831 BufferSize = sizeof (ConfigFormEntry->SessionConfigData);\r
832 Status = gRT->GetVariable (\r
833 ConfigFormEntry->MacString,\r
834 &gEfiIScsiInitiatorNameProtocolGuid,\r
835 NULL,\r
836 &BufferSize,\r
837 &ConfigFormEntry->SessionConfigData\r
838 );\r
839 if (EFI_ERROR (Status)) {\r
840 ZeroMem (&ConfigFormEntry->SessionConfigData, sizeof (ConfigFormEntry->SessionConfigData));\r
841 }\r
842 //\r
843 // Get the CHAP authentication configuration data.\r
844 //\r
845 BufferSize = sizeof (ConfigFormEntry->AuthConfigData);\r
846 Status = gRT->GetVariable (\r
847 ConfigFormEntry->MacString,\r
848 &mIScsiCHAPAuthInfoGuid,\r
849 NULL,\r
850 &BufferSize,\r
851 &ConfigFormEntry->AuthConfigData\r
852 );\r
853 if (EFI_ERROR (Status)) {\r
854 ZeroMem (&ConfigFormEntry->AuthConfigData, sizeof (ConfigFormEntry->AuthConfigData));\r
855 }\r
856 //\r
857 // Compose the Port string and create a new EFI_STRING_ID.\r
858 //\r
859 UnicodeSPrint (PortString, 128, L"Port %s", ConfigFormEntry->MacString);\r
860 ConfigFormEntry->PortTitleToken = HiiSetString (mCallbackInfo->RegisteredHandle, 0, PortString, NULL);\r
861\r
862 //\r
863 // Compose the help string of this port and create a new EFI_STRING_ID.\r
864 //\r
865 UnicodeSPrint (PortString, 128, L"Set the iSCSI parameters on port %s", ConfigFormEntry->MacString);\r
866 ConfigFormEntry->PortTitleHelpToken = HiiSetString (mCallbackInfo->RegisteredHandle, 0, PortString, NULL);\r
867\r
868 InsertTailList (&mIScsiConfigFormList, &ConfigFormEntry->Link);\r
869 mNumberOfIScsiDevices++;\r
870 }\r
871 } else {\r
872 ASSERT (EntryExisted);\r
873\r
874 mNumberOfIScsiDevices--;\r
875 RemoveEntryList (&ConfigFormEntry->Link);\r
876 gBS->FreePool (ConfigFormEntry);\r
877 }\r
878 //\r
879 // Allocate space for creation of Buffer\r
880 //\r
881\r
882 //\r
883 // Init OpCode Handle\r
884 //\r
885 StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
886 ASSERT (StartOpCodeHandle != NULL);\r
887\r
888 EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
889 ASSERT (EndOpCodeHandle != NULL);\r
890\r
891 //\r
892 // Create Hii Extend Label OpCode as the start opcode\r
893 //\r
894 StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));\r
895 StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
896 StartLabel->Number = DEVICE_ENTRY_LABEL;\r
897\r
898 //\r
899 // Create Hii Extend Label OpCode as the end opcode\r
900 //\r
901 EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));\r
902 EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
903 EndLabel->Number = LABEL_END;\r
904\r
905 FormIndex = 0;\r
906 NET_LIST_FOR_EACH (Entry, &mIScsiConfigFormList) {\r
907 ConfigFormEntry = NET_LIST_USER_STRUCT (Entry, ISCSI_CONFIG_FORM_ENTRY, Link);\r
908\r
909 HiiCreateGotoOpCode (\r
910 StartOpCodeHandle, // Container for dynamic created opcodes\r
911 FORMID_DEVICE_FORM, // Target Form ID\r
912 ConfigFormEntry->PortTitleToken, // Prompt text\r
913 ConfigFormEntry->PortTitleHelpToken, // Help text\r
914 EFI_IFR_FLAG_CALLBACK, // Question flag\r
915 (UINT16)(KEY_DEVICE_ENTRY_BASE + FormIndex) // Question ID\r
916 );\r
917\r
918 FormIndex++;\r
919 }\r
920\r
921 HiiUpdateForm (\r
922 mCallbackInfo->RegisteredHandle,\r
923 &mVendorGuid,\r
924 FORMID_MAIN_FORM,\r
925 StartOpCodeHandle, // Label DEVICE_ENTRY_LABEL\r
926 EndOpCodeHandle // LABEL_END\r
927 );\r
928\r
929 HiiFreeOpCodeHandle (StartOpCodeHandle);\r
930 HiiFreeOpCodeHandle (EndOpCodeHandle);\r
931\r
932 return EFI_SUCCESS;\r
933}\r
934\r
935/**\r
936 Initialize the iSCSI configuration form.\r
937\r
938 @param[in] DriverBindingHandle The iSCSI driverbinding handle.\r
939\r
940 @retval EFI_SUCCESS The iSCSI configuration form is initialized.\r
941 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
942 @retval Others Other errors as indicated.\r
943**/\r
944EFI_STATUS\r
945IScsiConfigFormInit (\r
946 VOID\r
947 )\r
948{\r
949 EFI_STATUS Status;\r
950 EFI_HII_DATABASE_PROTOCOL *HiiDatabase;\r
951 ISCSI_FORM_CALLBACK_INFO *CallbackInfo;\r
952\r
953 Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **)&HiiDatabase);\r
954 if (EFI_ERROR (Status)) {\r
955 return Status;\r
956 }\r
957\r
958 CallbackInfo = (ISCSI_FORM_CALLBACK_INFO *) AllocateZeroPool (sizeof (ISCSI_FORM_CALLBACK_INFO));\r
959 if (CallbackInfo == NULL) {\r
960 return EFI_OUT_OF_RESOURCES;\r
961 }\r
962\r
963 CallbackInfo->Signature = ISCSI_FORM_CALLBACK_INFO_SIGNATURE;\r
964 CallbackInfo->HiiDatabase = HiiDatabase;\r
965 CallbackInfo->Current = NULL;\r
966\r
967 CallbackInfo->ConfigAccess.ExtractConfig = IScsiFormExtractConfig;\r
968 CallbackInfo->ConfigAccess.RouteConfig = IScsiFormRouteConfig;\r
969 CallbackInfo->ConfigAccess.Callback = IScsiFormCallback;\r
970\r
971 Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **)&CallbackInfo->ConfigRouting);\r
972 if (EFI_ERROR (Status)) {\r
973 FreePool(CallbackInfo);\r
974 return Status;\r
975 }\r
976\r
977 //\r
978 // Install Device Path Protocol and Config Access protocol to driver handle\r
979 //\r
980 Status = gBS->InstallMultipleProtocolInterfaces (\r
981 &CallbackInfo->DriverHandle,\r
982 &gEfiDevicePathProtocolGuid,\r
983 &mIScsiHiiVendorDevicePath,\r
984 &gEfiHiiConfigAccessProtocolGuid,\r
985 &CallbackInfo->ConfigAccess,\r
986 NULL\r
987 );\r
988 ASSERT_EFI_ERROR (Status);\r
989 \r
990 //\r
991 // Publish our HII data\r
992 //\r
993 CallbackInfo->RegisteredHandle = HiiAddPackages (\r
994 &mVendorGuid,\r
995 CallbackInfo->DriverHandle,\r
996 IScsiDxeStrings,\r
997 IScsiConfigDxeBin,\r
998 NULL\r
999 );\r
1000 if (CallbackInfo->RegisteredHandle == NULL) {\r
1001 FreePool(CallbackInfo);\r
1002 return EFI_OUT_OF_RESOURCES;\r
1003 }\r
1004\r
1005 mCallbackInfo = CallbackInfo;\r
1006\r
1007 return Status;\r
1008}\r
1009\r
1010/**\r
1011 Unload the iSCSI configuration form, this includes: delete all the iSCSI\r
1012 device configuration entries, uninstall the form callback protocol and\r
1013 free the resources used.\r
1014\r
1015 @param[in] DriverBindingHandle The iSCSI driverbinding handle.\r
1016 \r
1017 @retval EFI_SUCCESS The iSCSI configuration form is unloaded.\r
1018 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
1019**/\r
1020EFI_STATUS\r
1021IScsiConfigFormUnload (\r
1022 IN EFI_HANDLE DriverBindingHandle\r
1023 )\r
1024{\r
1025 ISCSI_CONFIG_FORM_ENTRY *ConfigFormEntry;\r
1026\r
1027 while (!IsListEmpty (&mIScsiConfigFormList)) {\r
1028 //\r
1029 // Uninstall the device forms as the iSCSI driver instance may fail to\r
1030 // control the controller but still install the device configuration form.\r
1031 // In such case, upon driver unloading, the driver instance's driverbinding.\r
1032 // stop () won't be called, so we have to take this chance here to uninstall\r
1033 // the device form.\r
1034 //\r
1035 ConfigFormEntry = NET_LIST_USER_STRUCT (mIScsiConfigFormList.ForwardLink, ISCSI_CONFIG_FORM_ENTRY, Link);\r
1036 IScsiConfigUpdateForm (DriverBindingHandle, ConfigFormEntry->Controller, FALSE);\r
1037 }\r
1038\r
1039 //\r
1040 // Remove HII package list\r
1041 //\r
1042 mCallbackInfo->HiiDatabase->RemovePackageList (\r
1043 mCallbackInfo->HiiDatabase,\r
1044 mCallbackInfo->RegisteredHandle\r
1045 );\r
1046\r
1047 //\r
1048 // Uninstall EFI_HII_CONFIG_ACCESS_PROTOCOL\r
1049 //\r
1050 gBS->UninstallMultipleProtocolInterfaces (\r
1051 mCallbackInfo->DriverHandle,\r
1052 &gEfiDevicePathProtocolGuid,\r
1053 &mIScsiHiiVendorDevicePath,\r
1054 &gEfiHiiConfigAccessProtocolGuid,\r
1055 &mCallbackInfo->ConfigAccess,\r
1056 NULL\r
1057 );\r
1058 gBS->FreePool (mCallbackInfo);\r
1059\r
1060 return EFI_SUCCESS;\r
1061}\r