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