]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - NetworkPkg/IScsiDxe/IScsiDriver.c
Open default Tcp child via BY_CHILD_CONTROLLER.
[mirror_edk2.git] / NetworkPkg / IScsiDxe / IScsiDriver.c
... / ...
CommitLineData
1/** @file\r
2 The entry point of IScsi driver.\r
3\r
4Copyright (c) 2004 - 2015, 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
17EFI_DRIVER_BINDING_PROTOCOL gIScsiIp4DriverBinding = {\r
18 IScsiIp4DriverBindingSupported,\r
19 IScsiIp4DriverBindingStart,\r
20 IScsiIp4DriverBindingStop,\r
21 0xa,\r
22 NULL,\r
23 NULL\r
24};\r
25\r
26EFI_DRIVER_BINDING_PROTOCOL gIScsiIp6DriverBinding = {\r
27 IScsiIp6DriverBindingSupported,\r
28 IScsiIp6DriverBindingStart,\r
29 IScsiIp6DriverBindingStop,\r
30 0xa,\r
31 NULL,\r
32 NULL\r
33};\r
34\r
35EFI_GUID gIScsiV4PrivateGuid = ISCSI_V4_PRIVATE_GUID;\r
36EFI_GUID gIScsiV6PrivateGuid = ISCSI_V6_PRIVATE_GUID;\r
37ISCSI_PRIVATE_DATA *mPrivate = NULL;\r
38\r
39/**\r
40 Tests to see if this driver supports the RemainingDevicePath. \r
41\r
42 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This \r
43 parameter is ignored by device drivers, and is optional for bus \r
44 drivers. For bus drivers, if this parameter is not NULL, then \r
45 the bus driver must determine if the bus controller specified \r
46 by ControllerHandle and the child controller specified \r
47 by RemainingDevicePath are both supported by this \r
48 bus driver.\r
49\r
50 @retval EFI_SUCCESS The RemainingDevicePath is supported or NULL.\r
51 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
52 RemainingDevicePath is not supported by the driver specified by This.\r
53**/\r
54EFI_STATUS\r
55IScsiIsDevicePathSupported (\r
56 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
57 )\r
58{\r
59 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
60\r
61 CurrentDevicePath = RemainingDevicePath;\r
62 if (CurrentDevicePath != NULL) {\r
63 while (!IsDevicePathEnd (CurrentDevicePath)) {\r
64 if ((CurrentDevicePath->Type == MESSAGING_DEVICE_PATH) && (CurrentDevicePath->SubType == MSG_ISCSI_DP)) {\r
65 return EFI_SUCCESS;\r
66 }\r
67\r
68 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);\r
69 }\r
70\r
71 return EFI_UNSUPPORTED;\r
72 }\r
73\r
74 return EFI_SUCCESS;\r
75}\r
76\r
77\r
78/**\r
79 Tests to see if this driver supports a given controller. This is the worker function for\r
80 IScsiIp4(6)DriverBindingSupported.\r
81\r
82 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
83 @param[in] ControllerHandle The handle of the controller to test. This handle \r
84 must support a protocol interface that supplies \r
85 an I/O abstraction to the driver.\r
86 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This \r
87 parameter is ignored by device drivers, and is optional for bus \r
88 drivers. For bus drivers, if this parameter is not NULL, then \r
89 the bus driver must determine if the bus controller specified \r
90 by ControllerHandle and the child controller specified \r
91 by RemainingDevicePath are both supported by this \r
92 bus driver.\r
93 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.\r
94\r
95 @retval EFI_SUCCESS The device specified by ControllerHandle and\r
96 RemainingDevicePath is supported by the driver specified by This.\r
97 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
98 RemainingDevicePath is already being managed by the driver\r
99 specified by This.\r
100 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
101 RemainingDevicePath is not supported by the driver specified by This.\r
102**/\r
103EFI_STATUS\r
104EFIAPI\r
105IScsiSupported (\r
106 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
107 IN EFI_HANDLE ControllerHandle,\r
108 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL,\r
109 IN UINT8 IpVersion\r
110 )\r
111{\r
112 EFI_STATUS Status;\r
113 EFI_GUID *IScsiServiceBindingGuid;\r
114 EFI_GUID *TcpServiceBindingGuid;\r
115 EFI_GUID *DhcpServiceBindingGuid;\r
116\r
117 if (IpVersion == IP_VERSION_4) {\r
118 IScsiServiceBindingGuid = &gIScsiV4PrivateGuid;\r
119 TcpServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;\r
120 DhcpServiceBindingGuid = &gEfiDhcp4ServiceBindingProtocolGuid;\r
121 } else {\r
122 IScsiServiceBindingGuid = &gIScsiV6PrivateGuid;\r
123 TcpServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;\r
124 DhcpServiceBindingGuid = &gEfiDhcp6ServiceBindingProtocolGuid;\r
125 }\r
126\r
127 Status = gBS->OpenProtocol (\r
128 ControllerHandle,\r
129 IScsiServiceBindingGuid,\r
130 NULL,\r
131 This->DriverBindingHandle,\r
132 ControllerHandle,\r
133 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
134 );\r
135 if (!EFI_ERROR (Status)) {\r
136 return EFI_ALREADY_STARTED;\r
137 }\r
138\r
139 Status = gBS->OpenProtocol (\r
140 ControllerHandle,\r
141 TcpServiceBindingGuid,\r
142 NULL,\r
143 This->DriverBindingHandle,\r
144 ControllerHandle,\r
145 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
146 );\r
147 if (EFI_ERROR (Status)) {\r
148 return EFI_UNSUPPORTED;\r
149 }\r
150\r
151 Status = IScsiIsDevicePathSupported (RemainingDevicePath);\r
152 if (EFI_ERROR (Status)) {\r
153 return EFI_UNSUPPORTED;\r
154 }\r
155\r
156 if (IScsiDhcpIsConfigured (ControllerHandle, IpVersion)) {\r
157 Status = gBS->OpenProtocol (\r
158 ControllerHandle,\r
159 DhcpServiceBindingGuid,\r
160 NULL,\r
161 This->DriverBindingHandle,\r
162 ControllerHandle,\r
163 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
164 );\r
165 if (EFI_ERROR (Status)) {\r
166 return EFI_UNSUPPORTED;\r
167 }\r
168 }\r
169 \r
170 return EFI_SUCCESS;\r
171}\r
172\r
173\r
174/**\r
175 Start to manage the controller. This is the worker function for\r
176 IScsiIp4(6)DriverBindingStart.\r
177\r
178 @param[in] Image Handle of the image.\r
179 @param[in] ControllerHandle Handle of the controller.\r
180 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.\r
181\r
182 @retval EFI_SUCCES This driver was started.\r
183 @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
184 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
185 @retval EFI_NOT_FOUND There is no sufficient information to establish\r
186 the iScsi session.\r
187 @retval EFI_DEVICE_ERROR Failed to get TCP connection device path. \r
188\r
189**/\r
190EFI_STATUS\r
191IScsiStart (\r
192 IN EFI_HANDLE Image,\r
193 IN EFI_HANDLE ControllerHandle,\r
194 IN UINT8 IpVersion\r
195 )\r
196{\r
197 EFI_STATUS Status;\r
198 ISCSI_DRIVER_DATA *Private;\r
199 LIST_ENTRY *Entry;\r
200 LIST_ENTRY *NextEntry;\r
201 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;\r
202 ISCSI_SESSION *Session;\r
203 UINT8 Index;\r
204 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExistIScsiExtScsiPassThru;\r
205 ISCSI_DRIVER_DATA *ExistPrivate;\r
206 UINT8 *AttemptConfigOrder;\r
207 UINTN AttemptConfigOrderSize;\r
208 UINT8 BootSelected;\r
209 EFI_HANDLE *HandleBuffer;\r
210 UINTN NumberOfHandles;\r
211 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
212 EFI_GUID *IScsiPrivateGuid;\r
213 EFI_GUID *TcpServiceBindingGuid;\r
214 CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN];\r
215 BOOLEAN NeedUpdate;\r
216 VOID *Interface;\r
217 EFI_GUID *ProtocolGuid;\r
218\r
219 //\r
220 // Test to see if iSCSI driver supports the given controller.\r
221 //\r
222\r
223 if (IpVersion == IP_VERSION_4) {\r
224 IScsiPrivateGuid = &gIScsiV4PrivateGuid;\r
225 TcpServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;\r
226 ProtocolGuid = &gEfiTcp4ProtocolGuid;\r
227 } else if (IpVersion == IP_VERSION_6) {\r
228 IScsiPrivateGuid = &gIScsiV6PrivateGuid;\r
229 TcpServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;\r
230 ProtocolGuid = &gEfiTcp6ProtocolGuid;\r
231 } else {\r
232 return EFI_INVALID_PARAMETER;\r
233 }\r
234\r
235 Status = gBS->OpenProtocol (\r
236 ControllerHandle,\r
237 IScsiPrivateGuid,\r
238 NULL,\r
239 Image,\r
240 ControllerHandle,\r
241 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
242 );\r
243 if (!EFI_ERROR (Status)) {\r
244 return EFI_ALREADY_STARTED;\r
245 }\r
246\r
247 Status = gBS->OpenProtocol (\r
248 ControllerHandle,\r
249 TcpServiceBindingGuid,\r
250 NULL,\r
251 Image,\r
252 ControllerHandle,\r
253 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
254 );\r
255 if (EFI_ERROR (Status)) {\r
256 return EFI_UNSUPPORTED;\r
257 }\r
258\r
259 //\r
260 // Record the incoming NIC info.\r
261 //\r
262 Status = IScsiAddNic (ControllerHandle);\r
263 if (EFI_ERROR (Status)) {\r
264 return Status;\r
265 }\r
266\r
267 //\r
268 // Create the instance private data.\r
269 //\r
270 Private = IScsiCreateDriverData (Image, ControllerHandle);\r
271 if (Private == NULL) {\r
272 return EFI_OUT_OF_RESOURCES;\r
273 }\r
274\r
275 //\r
276 // Create a underlayer child instance, but not need to configure it. Just open ChildHandle\r
277 // via BY_DRIVER. That is, establishing the relationship between ControllerHandle and ChildHandle.\r
278 // Therefore, when DisconnectController(), especially VLAN virtual controller handle,\r
279 // IScsiDriverBindingStop() will be called.\r
280 //\r
281 Status = NetLibCreateServiceChild (\r
282 ControllerHandle,\r
283 Image,\r
284 TcpServiceBindingGuid,\r
285 &Private->ChildHandle\r
286 );\r
287\r
288 if (EFI_ERROR (Status)) {\r
289 goto ON_ERROR;\r
290 }\r
291\r
292 Status = gBS->OpenProtocol (\r
293 Private->ChildHandle, /// Default Tcp child\r
294 ProtocolGuid,\r
295 &Interface,\r
296 Image,\r
297 ControllerHandle,\r
298 EFI_OPEN_PROTOCOL_BY_DRIVER\r
299 );\r
300 \r
301 if (EFI_ERROR (Status)) {\r
302 goto ON_ERROR;\r
303 }\r
304\r
305 //\r
306 // Always install private protocol no matter what happens later. We need to \r
307 // keep the relationship between ControllerHandle and ChildHandle.\r
308 //\r
309 Status = gBS->InstallProtocolInterface (\r
310 &ControllerHandle,\r
311 IScsiPrivateGuid,\r
312 EFI_NATIVE_INTERFACE,\r
313 &Private->IScsiIdentifier\r
314 );\r
315 if (EFI_ERROR (Status)) {\r
316 goto ON_ERROR;\r
317 }\r
318 \r
319 if (IpVersion == IP_VERSION_4) {\r
320 mPrivate->Ipv6Flag = FALSE;\r
321 } else {\r
322 mPrivate->Ipv6Flag = TRUE;\r
323 }\r
324\r
325 //\r
326 // Get the current iSCSI configuration data.\r
327 //\r
328 Status = IScsiGetConfigData (Private);\r
329 if (EFI_ERROR (Status)) {\r
330 goto ON_ERROR;\r
331 }\r
332\r
333 //\r
334 // If there is already a successul attempt, check whether this attempt is the\r
335 // first "enabled for MPIO" attempt. If not, still try the first attempt.\r
336 // In single path mode, try all attempts.\r
337 //\r
338 ExistPrivate = NULL;\r
339 Status = EFI_NOT_FOUND;\r
340\r
341 if (mPrivate->OneSessionEstablished && mPrivate->EnableMpio) {\r
342 AttemptConfigData = NULL;\r
343 NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {\r
344 AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);\r
345 if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {\r
346 break;\r
347 }\r
348 }\r
349\r
350 if (AttemptConfigData == NULL) {\r
351 goto ON_ERROR;\r
352 }\r
353\r
354 if (AttemptConfigData->AttemptConfigIndex == mPrivate->BootSelectedIndex) {\r
355 goto ON_EXIT;\r
356 }\r
357\r
358 //\r
359 // Uninstall the original ExtScsiPassThru first.\r
360 //\r
361\r
362 //\r
363 // Locate all ExtScsiPassThru protocol instances.\r
364 //\r
365 Status = gBS->LocateHandleBuffer (\r
366 ByProtocol,\r
367 &gEfiExtScsiPassThruProtocolGuid,\r
368 NULL,\r
369 &NumberOfHandles,\r
370 &HandleBuffer\r
371 );\r
372 if (EFI_ERROR (Status)) {\r
373 goto ON_ERROR;\r
374 }\r
375\r
376 //\r
377 // Find ExtScsiPassThru protocol instance produced by this driver.\r
378 //\r
379 ExistIScsiExtScsiPassThru = NULL;\r
380 for (Index = 0; Index < NumberOfHandles && ExistIScsiExtScsiPassThru == NULL; Index++) {\r
381 Status = gBS->HandleProtocol (\r
382 HandleBuffer[Index],\r
383 &gEfiDevicePathProtocolGuid,\r
384 (VOID **) &DevicePath\r
385 );\r
386 if (EFI_ERROR (Status)) {\r
387 continue;\r
388 }\r
389\r
390 while (!IsDevicePathEnd (DevicePath)) {\r
391 if ((DevicePath->Type == MESSAGING_DEVICE_PATH) && (DevicePath->SubType == MSG_MAC_ADDR_DP)) {\r
392 //\r
393 // Get the ExtScsiPassThru protocol instance.\r
394 //\r
395 Status = gBS->HandleProtocol (\r
396 HandleBuffer[Index],\r
397 &gEfiExtScsiPassThruProtocolGuid,\r
398 (VOID **) &ExistIScsiExtScsiPassThru\r
399 );\r
400 ASSERT_EFI_ERROR (Status);\r
401 break;\r
402 }\r
403\r
404 DevicePath = NextDevicePathNode (DevicePath);\r
405 }\r
406 }\r
407\r
408 FreePool (HandleBuffer);\r
409\r
410 if (ExistIScsiExtScsiPassThru == NULL) {\r
411 Status = EFI_NOT_FOUND;\r
412 goto ON_ERROR;\r
413 }\r
414\r
415 ExistPrivate = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (ExistIScsiExtScsiPassThru);\r
416\r
417 Status = gBS->UninstallProtocolInterface (\r
418 ExistPrivate->ExtScsiPassThruHandle,\r
419 &gEfiExtScsiPassThruProtocolGuid,\r
420 &ExistPrivate->IScsiExtScsiPassThru\r
421 );\r
422 if (EFI_ERROR (Status)) {\r
423 goto ON_ERROR;\r
424 }\r
425 }\r
426\r
427 //\r
428 // Install the Ext SCSI PASS THRU protocol.\r
429 //\r
430 Status = gBS->InstallProtocolInterface (\r
431 &Private->ExtScsiPassThruHandle,\r
432 &gEfiExtScsiPassThruProtocolGuid,\r
433 EFI_NATIVE_INTERFACE,\r
434 &Private->IScsiExtScsiPassThru\r
435 );\r
436 if (EFI_ERROR (Status)) {\r
437 goto ON_ERROR;\r
438 }\r
439\r
440 BootSelected = 0;\r
441\r
442 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mPrivate->AttemptConfigs) {\r
443 AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);\r
444 //\r
445 // Don't process the attempt that does not associate with the current NIC or\r
446 // this attempt is disabled or established.\r
447 //\r
448 if (AttemptConfigData->NicIndex != mPrivate->CurrentNic ||\r
449 AttemptConfigData->SessionConfigData.Enabled == ISCSI_DISABLED ||\r
450 AttemptConfigData->ValidPath) {\r
451 continue;\r
452 }\r
453\r
454 //\r
455 // In multipath mode, don't process attempts configured for single path.\r
456 // In default single path mode, don't process attempts configured for multipath.\r
457 //\r
458 if ((mPrivate->EnableMpio &&\r
459 AttemptConfigData->SessionConfigData.Enabled != ISCSI_ENABLED_FOR_MPIO) ||\r
460 (!mPrivate->EnableMpio &&\r
461 AttemptConfigData->SessionConfigData.Enabled != ISCSI_ENABLED)) {\r
462 continue;\r
463 }\r
464\r
465 //\r
466 // Don't process the attempt that fails to get the init/target information from DHCP.\r
467 //\r
468 if (AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp &&\r
469 !AttemptConfigData->DhcpSuccess) {\r
470 if (!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount > 0) {\r
471 mPrivate->ValidSinglePathCount--;\r
472 }\r
473 continue;\r
474 }\r
475\r
476 //\r
477 // Don't process the autoconfigure path if it is already established.\r
478 //\r
479 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&\r
480 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_SUCCESS) {\r
481 continue;\r
482 }\r
483\r
484 //\r
485 // Don't process the attempt if its IP mode is not in the current IP version.\r
486 //\r
487 if (!mPrivate->Ipv6Flag) {\r
488 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6) {\r
489 continue;\r
490 }\r
491 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&\r
492 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6) {\r
493 continue;\r
494 }\r
495 } else {\r
496 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4) {\r
497 continue;\r
498 }\r
499 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&\r
500 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4) {\r
501 continue;\r
502 }\r
503 }\r
504\r
505 //\r
506 // Fill in the Session and init it.\r
507 //\r
508 Session = (ISCSI_SESSION *) AllocateZeroPool (sizeof (ISCSI_SESSION));\r
509 if (Session == NULL) {\r
510 Status = EFI_OUT_OF_RESOURCES;\r
511 goto ON_ERROR;\r
512 }\r
513\r
514 Session->Private = Private;\r
515 Session->ConfigData = AttemptConfigData;\r
516 Session->AuthType = AttemptConfigData->AuthenticationType;\r
517\r
518 AsciiStrToUnicodeStr (AttemptConfigData->MacString, MacString);\r
519 UnicodeSPrint (\r
520 mPrivate->PortString,\r
521 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
522 L"%s%d",\r
523 MacString,\r
524 (UINTN) AttemptConfigData->AttemptConfigIndex\r
525 );\r
526\r
527 if (Session->AuthType == ISCSI_AUTH_TYPE_CHAP) {\r
528 Session->AuthData.CHAP.AuthConfig = &AttemptConfigData->AuthConfigData.CHAP;\r
529 }\r
530\r
531 IScsiSessionInit (Session, FALSE);\r
532\r
533 //\r
534 // Try to login and create an iSCSI session according to the configuration.\r
535 //\r
536 Status = IScsiSessionLogin (Session);\r
537 if (Status == EFI_MEDIA_CHANGED) {\r
538 //\r
539 // The specified target is not available, and the redirection information is\r
540 // received. Login the session again with the updated target address.\r
541 //\r
542 Status = IScsiSessionLogin (Session);\r
543 } else if (Status == EFI_NOT_READY) {\r
544 Status = IScsiSessionReLogin (Session);\r
545 }\r
546\r
547 if (EFI_ERROR (Status)) {\r
548 //\r
549 // In Single path mode, only the successful attempt will be recorded in iBFT;\r
550 // in multi-path mode, all the attempt entries in MPIO will be recorded in iBFT.\r
551 //\r
552 if (!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount > 0) {\r
553 mPrivate->ValidSinglePathCount--;\r
554 }\r
555\r
556 FreePool (Session);\r
557\r
558 } else {\r
559 AttemptConfigData->ValidPath = TRUE;\r
560\r
561 //\r
562 // Do not record the attempt in iBFT if it login with KRB5.\r
563 // TODO: record KRB5 attempt information in the iSCSI device path.\r
564 //\r
565 if (Session->AuthType == ISCSI_AUTH_TYPE_KRB) {\r
566 if (!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount > 0) {\r
567 mPrivate->ValidSinglePathCount--;\r
568 }\r
569\r
570 AttemptConfigData->ValidiBFTPath = FALSE;\r
571 } else {\r
572 AttemptConfigData->ValidiBFTPath = TRUE;\r
573 }\r
574\r
575 //\r
576 // IScsi session success. Update the attempt state to NVR.\r
577 //\r
578 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {\r
579 AttemptConfigData->AutoConfigureMode = IP_MODE_AUTOCONFIG_SUCCESS;\r
580 }\r
581\r
582 gRT->SetVariable (\r
583 mPrivate->PortString,\r
584 &gEfiIScsiInitiatorNameProtocolGuid,\r
585 ISCSI_CONFIG_VAR_ATTR,\r
586 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),\r
587 AttemptConfigData\r
588 );\r
589\r
590 //\r
591 // Select the first login session. Abort others.\r
592 //\r
593 if (Private->Session == NULL) {\r
594 Private->Session = Session;\r
595 BootSelected = AttemptConfigData->AttemptConfigIndex;\r
596 //\r
597 // Don't validate other attempt in multipath mode if one is success.\r
598 //\r
599 if (mPrivate->EnableMpio) {\r
600 break;\r
601 }\r
602 } else {\r
603 IScsiSessionAbort (Session);\r
604 FreePool (Session);\r
605 }\r
606 }\r
607 }\r
608\r
609 //\r
610 // All attempts configured for this driver instance are not valid.\r
611 //\r
612 if (Private->Session == NULL) {\r
613 Status = gBS->UninstallProtocolInterface (\r
614 Private->ExtScsiPassThruHandle,\r
615 &gEfiExtScsiPassThruProtocolGuid,\r
616 &Private->IScsiExtScsiPassThru\r
617 );\r
618 ASSERT_EFI_ERROR (Status);\r
619 Private->ExtScsiPassThruHandle = NULL;\r
620\r
621 //\r
622 // Reinstall the original ExtScsiPassThru back.\r
623 //\r
624 if (mPrivate->OneSessionEstablished && ExistPrivate != NULL) {\r
625 Status = gBS->InstallProtocolInterface (\r
626 &ExistPrivate->ExtScsiPassThruHandle,\r
627 &gEfiExtScsiPassThruProtocolGuid,\r
628 EFI_NATIVE_INTERFACE,\r
629 &ExistPrivate->IScsiExtScsiPassThru\r
630 );\r
631 if (EFI_ERROR (Status)) {\r
632 goto ON_ERROR;\r
633 }\r
634\r
635 goto ON_EXIT;\r
636 }\r
637\r
638 Status = EFI_NOT_FOUND;\r
639\r
640 goto ON_ERROR;\r
641 }\r
642\r
643 NeedUpdate = TRUE;\r
644 //\r
645 // More than one attempt successes.\r
646 //\r
647 if (Private->Session != NULL && mPrivate->OneSessionEstablished) {\r
648\r
649 AttemptConfigOrder = IScsiGetVariableAndSize (\r
650 L"AttemptOrder",\r
651 &gIScsiConfigGuid,\r
652 &AttemptConfigOrderSize\r
653 );\r
654 if (AttemptConfigOrder == NULL) {\r
655 goto ON_ERROR;\r
656 }\r
657 for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {\r
658 if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex ||\r
659 AttemptConfigOrder[Index] == BootSelected) {\r
660 break;\r
661 }\r
662 }\r
663\r
664 if (mPrivate->EnableMpio) {\r
665 //\r
666 // Use the attempt in earlier order. Abort the later one in MPIO.\r
667 //\r
668 if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex) {\r
669 IScsiSessionAbort (Private->Session);\r
670 FreePool (Private->Session);\r
671 Private->Session = NULL;\r
672 gBS->UninstallProtocolInterface (\r
673 Private->ExtScsiPassThruHandle,\r
674 &gEfiExtScsiPassThruProtocolGuid,\r
675 &Private->IScsiExtScsiPassThru\r
676 );\r
677 Private->ExtScsiPassThruHandle = NULL;\r
678\r
679 //\r
680 // Reinstall the original ExtScsiPassThru back.\r
681 //\r
682 Status = gBS->InstallProtocolInterface (\r
683 &ExistPrivate->ExtScsiPassThruHandle,\r
684 &gEfiExtScsiPassThruProtocolGuid,\r
685 EFI_NATIVE_INTERFACE,\r
686 &ExistPrivate->IScsiExtScsiPassThru\r
687 );\r
688 if (EFI_ERROR (Status)) {\r
689 goto ON_ERROR;\r
690 }\r
691\r
692 goto ON_EXIT;\r
693 } else {\r
694 if (AttemptConfigOrder[Index] != BootSelected) {\r
695 goto ON_ERROR;\r
696 }\r
697 mPrivate->BootSelectedIndex = BootSelected;\r
698 //\r
699 // Clear the resource in ExistPrivate.\r
700 //\r
701 gBS->UninstallProtocolInterface (\r
702 ExistPrivate->Controller,\r
703 IScsiPrivateGuid,\r
704 &ExistPrivate->IScsiIdentifier\r
705 ); \r
706 \r
707 IScsiRemoveNic (ExistPrivate->Controller);\r
708 if (ExistPrivate->Session != NULL) {\r
709 IScsiSessionAbort (ExistPrivate->Session);\r
710 }\r
711\r
712 IScsiCleanDriverData (ExistPrivate);\r
713 }\r
714 } else {\r
715 //\r
716 // Use the attempt in earlier order as boot selected in single path mode.\r
717 //\r
718 if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex) {\r
719 NeedUpdate = FALSE;\r
720 }\r
721 }\r
722\r
723 }\r
724\r
725 if (NeedUpdate) {\r
726 mPrivate->OneSessionEstablished = TRUE;\r
727 mPrivate->BootSelectedIndex = BootSelected;\r
728 }\r
729\r
730 //\r
731 // Duplicate the Session's tcp connection device path. The source port field\r
732 // will be set to zero as one iSCSI session is comprised of several iSCSI\r
733 // connections.\r
734 //\r
735 Private->DevicePath = IScsiGetTcpConnDevicePath (Private->Session);\r
736 if (Private->DevicePath == NULL) {\r
737 Status = EFI_DEVICE_ERROR;\r
738 goto ON_ERROR;\r
739 }\r
740 //\r
741 // Install the updated device path onto the ExtScsiPassThruHandle.\r
742 //\r
743 Status = gBS->InstallProtocolInterface (\r
744 &Private->ExtScsiPassThruHandle,\r
745 &gEfiDevicePathProtocolGuid,\r
746 EFI_NATIVE_INTERFACE,\r
747 Private->DevicePath\r
748 );\r
749 if (EFI_ERROR (Status)) {\r
750 goto ON_ERROR;\r
751 }\r
752\r
753 //\r
754 // ISCSI children should share the default Tcp child, just open the default Tcp child via BY_CHILD_CONTROLLER.\r
755 //\r
756 Status = gBS->OpenProtocol (\r
757 Private->ChildHandle, /// Default Tcp child\r
758 ProtocolGuid,\r
759 &Interface,\r
760 Image,\r
761 Private->ExtScsiPassThruHandle,\r
762 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
763 ); \r
764 if (EFI_ERROR (Status)) {\r
765 gBS->UninstallMultipleProtocolInterfaces (\r
766 Private->ExtScsiPassThruHandle,\r
767 &gEfiExtScsiPassThruProtocolGuid,\r
768 &Private->IScsiExtScsiPassThru,\r
769 &gEfiDevicePathProtocolGuid,\r
770 Private->DevicePath,\r
771 NULL\r
772 );\r
773 \r
774 goto ON_ERROR;\r
775 }\r
776\r
777ON_EXIT:\r
778\r
779 //\r
780 // Update/Publish the iSCSI Boot Firmware Table.\r
781 //\r
782 if (mPrivate->BootSelectedIndex != 0) {\r
783 IScsiPublishIbft ();\r
784 }\r
785\r
786 return EFI_SUCCESS;\r
787\r
788ON_ERROR:\r
789\r
790 if (Private->Session != NULL) {\r
791 IScsiSessionAbort (Private->Session);\r
792 }\r
793\r
794 return Status;\r
795}\r
796\r
797/**\r
798 Stops a device controller or a bus controller. This is the worker function for\r
799 IScsiIp4(6)DriverBindingStop.\r
800 \r
801 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
802 @param[in] ControllerHandle A handle to the device being stopped. The handle must \r
803 support a bus specific I/O protocol for the driver \r
804 to use to stop the device.\r
805 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
806 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL \r
807 if NumberOfChildren is 0.\r
808 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.\r
809 \r
810 @retval EFI_SUCCESS The device was stopped.\r
811 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
812\r
813**/\r
814EFI_STATUS\r
815EFIAPI\r
816IScsiStop (\r
817 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
818 IN EFI_HANDLE ControllerHandle,\r
819 IN UINTN NumberOfChildren,\r
820 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL,\r
821 IN UINT8 IpVersion\r
822 )\r
823{\r
824 EFI_HANDLE IScsiController;\r
825 EFI_STATUS Status;\r
826 ISCSI_PRIVATE_PROTOCOL *IScsiIdentifier;\r
827 ISCSI_DRIVER_DATA *Private;\r
828 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;\r
829 ISCSI_CONNECTION *Conn;\r
830 EFI_GUID *ProtocolGuid;\r
831 EFI_GUID *TcpServiceBindingGuid;\r
832 EFI_GUID *TcpProtocolGuid;\r
833\r
834\r
835 if (NumberOfChildren != 0) {\r
836 //\r
837 // We should have only one child.\r
838 //\r
839 Status = gBS->OpenProtocol (\r
840 ChildHandleBuffer[0],\r
841 &gEfiExtScsiPassThruProtocolGuid,\r
842 (VOID **) &PassThru,\r
843 This->DriverBindingHandle,\r
844 ControllerHandle,\r
845 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
846 );\r
847 if (EFI_ERROR (Status)) {\r
848 return EFI_DEVICE_ERROR;\r
849 }\r
850\r
851 Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (PassThru);\r
852 Conn = NET_LIST_HEAD (&Private->Session->Conns, ISCSI_CONNECTION, Link);\r
853\r
854 //\r
855 // Previously the TCP protocol is opened BY_CHILD_CONTROLLER. Just close\r
856 // the protocol here, but do not uninstall the device path protocol and\r
857 // EXT SCSI PASS THRU protocol installed on ExtScsiPassThruHandle.\r
858 //\r
859 if (IpVersion == IP_VERSION_4) {\r
860 ProtocolGuid = &gEfiTcp4ProtocolGuid;\r
861 } else {\r
862 ProtocolGuid = &gEfiTcp6ProtocolGuid;\r
863 }\r
864\r
865 gBS->CloseProtocol (\r
866 Private->ChildHandle,\r
867 ProtocolGuid,\r
868 Private->Image,\r
869 Private->ExtScsiPassThruHandle\r
870 );\r
871 \r
872 gBS->CloseProtocol (\r
873 Conn->TcpIo.Handle,\r
874 ProtocolGuid,\r
875 Private->Image,\r
876 Private->ExtScsiPassThruHandle\r
877 );\r
878\r
879 return EFI_SUCCESS;\r
880 }\r
881 \r
882 //\r
883 // Get the handle of the controller we are controling.\r
884 //\r
885 if (IpVersion == IP_VERSION_4) {\r
886 ProtocolGuid = &gIScsiV4PrivateGuid;\r
887 TcpProtocolGuid = &gEfiTcp4ProtocolGuid;\r
888 TcpServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;\r
889 } else {\r
890 ProtocolGuid = &gIScsiV6PrivateGuid;\r
891 TcpProtocolGuid = &gEfiTcp6ProtocolGuid;\r
892 TcpServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;\r
893 }\r
894 IScsiController = NetLibGetNicHandle (ControllerHandle, TcpProtocolGuid);\r
895 if (IScsiController == NULL) {\r
896 return EFI_SUCCESS;\r
897 }\r
898\r
899 Status = gBS->OpenProtocol (\r
900 IScsiController,\r
901 ProtocolGuid,\r
902 (VOID **) &IScsiIdentifier,\r
903 This->DriverBindingHandle,\r
904 ControllerHandle,\r
905 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
906 );\r
907 if (EFI_ERROR (Status)) {\r
908 return EFI_DEVICE_ERROR;\r
909 }\r
910\r
911 Private = ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier);\r
912 ASSERT (Private != NULL);\r
913\r
914 if (Private->ChildHandle != NULL) {\r
915 Status = gBS->CloseProtocol (\r
916 Private->ChildHandle,\r
917 TcpProtocolGuid,\r
918 This->DriverBindingHandle,\r
919 IScsiController\r
920 );\r
921 \r
922 ASSERT (!EFI_ERROR (Status));\r
923\r
924 Status = NetLibDestroyServiceChild (\r
925 IScsiController,\r
926 This->DriverBindingHandle,\r
927 TcpServiceBindingGuid,\r
928 Private->ChildHandle\r
929 );\r
930\r
931 ASSERT (!EFI_ERROR (Status));\r
932 }\r
933\r
934 gBS->UninstallProtocolInterface (\r
935 IScsiController,\r
936 ProtocolGuid,\r
937 &Private->IScsiIdentifier\r
938 ); \r
939\r
940 //\r
941 // Remove this NIC.\r
942 //\r
943 IScsiRemoveNic (IScsiController);\r
944\r
945 //\r
946 // Update the iSCSI Boot Firware Table.\r
947 //\r
948 IScsiPublishIbft ();\r
949\r
950 if (Private->Session != NULL) {\r
951 IScsiSessionAbort (Private->Session);\r
952 }\r
953\r
954 IScsiCleanDriverData (Private);\r
955\r
956 return EFI_SUCCESS;\r
957}\r
958\r
959/**\r
960 Tests to see if this driver supports a given controller. If a child device is provided, \r
961 it tests to see if this driver supports creating a handle for the specified child device.\r
962\r
963 This function checks to see if the driver specified by This supports the device specified by \r
964 ControllerHandle. Drivers typically use the device path attached to \r
965 ControllerHandle and/or the services from the bus I/O abstraction attached to \r
966 ControllerHandle to determine if the driver supports ControllerHandle. This function \r
967 may be called many times during platform initialization. In order to reduce boot times, the tests \r
968 performed by this function must be very small and take as little time as possible to execute. This \r
969 function must not change the state of any hardware devices, and this function must be aware that the \r
970 device specified by ControllerHandle may already be managed by the same driver or a \r
971 different driver. This function must match its calls to AllocatePages() with FreePages(), \r
972 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). \r
973 Since ControllerHandle may have been previously started by the same driver, if a protocol is \r
974 already in the opened state, then it must not be closed with CloseProtocol(). This is required \r
975 to guarantee the state of ControllerHandle is not modified by this function.\r
976\r
977 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
978 @param[in] ControllerHandle The handle of the controller to test. This handle \r
979 must support a protocol interface that supplies \r
980 an I/O abstraction to the driver.\r
981 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This \r
982 parameter is ignored by device drivers, and is optional for bus \r
983 drivers. For bus drivers, if this parameter is not NULL, then \r
984 the bus driver must determine if the bus controller specified \r
985 by ControllerHandle and the child controller specified \r
986 by RemainingDevicePath are both supported by this \r
987 bus driver.\r
988\r
989 @retval EFI_SUCCESS The device specified by ControllerHandle and\r
990 RemainingDevicePath is supported by the driver specified by This.\r
991 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
992 RemainingDevicePath is already managed by the driver\r
993 specified by This.\r
994 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
995 RemainingDevicePath is already managed by a different\r
996 driver or an application that requires exclusive access.\r
997 Currently not implemented.\r
998 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
999 RemainingDevicePath is not supported by the driver specified by This.\r
1000**/\r
1001EFI_STATUS\r
1002EFIAPI\r
1003IScsiIp4DriverBindingSupported (\r
1004 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1005 IN EFI_HANDLE ControllerHandle,\r
1006 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
1007 )\r
1008{\r
1009 return IScsiSupported (\r
1010 This,\r
1011 ControllerHandle,\r
1012 RemainingDevicePath,\r
1013 IP_VERSION_4\r
1014 );\r
1015}\r
1016\r
1017/**\r
1018 Starts a device controller or a bus controller.\r
1019\r
1020 The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
1021 As a result, much of the error checking on the parameters to Start() has been moved into this \r
1022 common boot service. It is legal to call Start() from other locations, \r
1023 but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
1024 1. ControllerHandle must be a valid EFI_HANDLE.\r
1025 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
1026 EFI_DEVICE_PATH_PROTOCOL.\r
1027 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
1028 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. \r
1029\r
1030 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
1031 @param[in] ControllerHandle The handle of the controller to start. This handle \r
1032 must support a protocol interface that supplies \r
1033 an I/O abstraction to the driver.\r
1034 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This \r
1035 parameter is ignored by device drivers, and is optional for bus \r
1036 drivers. For a bus driver, if this parameter is NULL, then handles \r
1037 for all the children of Controller are created by this driver. \r
1038 If this parameter is not NULL and the first Device Path Node is \r
1039 not the End of Device Path Node, then only the handle for the \r
1040 child device specified by the first Device Path Node of \r
1041 RemainingDevicePath is created by this driver.\r
1042 If the first Device Path Node of RemainingDevicePath is \r
1043 the End of Device Path Node, no child handle is created by this\r
1044 driver.\r
1045\r
1046 @retval EFI_SUCCESS The device was started.\r
1047 @retval EFI_DEVICE_ERROR The device could not be started due to a device error. Currently not implemented.\r
1048 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
1049 @retval Others The driver failed to start the device.\r
1050\r
1051**/\r
1052EFI_STATUS\r
1053EFIAPI\r
1054IScsiIp4DriverBindingStart (\r
1055 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1056 IN EFI_HANDLE ControllerHandle,\r
1057 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
1058 )\r
1059{\r
1060 EFI_STATUS Status;\r
1061\r
1062 Status = IScsiStart (This->DriverBindingHandle, ControllerHandle, IP_VERSION_4);\r
1063 if (Status == EFI_ALREADY_STARTED) {\r
1064 Status = EFI_SUCCESS;\r
1065 }\r
1066\r
1067 return Status;\r
1068}\r
1069\r
1070/**\r
1071 Stops a device controller or a bus controller.\r
1072 \r
1073 The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). \r
1074 As a result, much of the error checking on the parameters to Stop() has been moved \r
1075 into this common boot service. It is legal to call Stop() from other locations, \r
1076 but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
1077 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
1078 same driver's Start() function.\r
1079 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
1080 EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
1081 Start() function, and the Start() function must have called OpenProtocol() on\r
1082 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
1083 \r
1084 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
1085 @param[in] ControllerHandle A handle to the device being stopped. The handle must \r
1086 support a bus specific I/O protocol for the driver \r
1087 to use to stop the device.\r
1088 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
1089 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL \r
1090 if NumberOfChildren is 0.\r
1091\r
1092 @retval EFI_SUCCESS The device was stopped.\r
1093 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
1094\r
1095**/\r
1096EFI_STATUS\r
1097EFIAPI\r
1098IScsiIp4DriverBindingStop (\r
1099 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1100 IN EFI_HANDLE ControllerHandle,\r
1101 IN UINTN NumberOfChildren,\r
1102 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL\r
1103 )\r
1104{\r
1105 return IScsiStop (\r
1106 This,\r
1107 ControllerHandle,\r
1108 NumberOfChildren,\r
1109 ChildHandleBuffer,\r
1110 IP_VERSION_4\r
1111 );\r
1112}\r
1113\r
1114/**\r
1115 Tests to see if this driver supports a given controller. If a child device is provided, \r
1116 it tests to see if this driver supports creating a handle for the specified child device.\r
1117\r
1118 This function checks to see if the driver specified by This supports the device specified by \r
1119 ControllerHandle. Drivers typically use the device path attached to \r
1120 ControllerHandle and/or the services from the bus I/O abstraction attached to \r
1121 ControllerHandle to determine if the driver supports ControllerHandle. This function \r
1122 may be called many times during platform initialization. In order to reduce boot times, the tests \r
1123 performed by this function must be very small and take as little time as possible to execute. This \r
1124 function must not change the state of any hardware devices, and this function must be aware that the \r
1125 device specified by ControllerHandle may already be managed by the same driver or a \r
1126 different driver. This function must match its calls to AllocatePages() with FreePages(), \r
1127 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). \r
1128 Since ControllerHandle may have been previously started by the same driver, if a protocol is \r
1129 already in the opened state, then it must not be closed with CloseProtocol(). This is required \r
1130 to guarantee the state of ControllerHandle is not modified by this function.\r
1131\r
1132 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
1133 @param[in] ControllerHandle The handle of the controller to test. This handle \r
1134 must support a protocol interface that supplies \r
1135 an I/O abstraction to the driver.\r
1136 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This \r
1137 parameter is ignored by device drivers, and is optional for bus \r
1138 drivers. For bus drivers, if this parameter is not NULL, then \r
1139 the bus driver must determine if the bus controller specified \r
1140 by ControllerHandle and the child controller specified \r
1141 by RemainingDevicePath are both supported by this \r
1142 bus driver.\r
1143\r
1144 @retval EFI_SUCCESS The device specified by ControllerHandle and\r
1145 RemainingDevicePath is supported by the driver specified by This.\r
1146 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
1147 RemainingDevicePath is already managed by the driver\r
1148 specified by This.\r
1149 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
1150 RemainingDevicePath is already managed by a different\r
1151 driver or an application that requires exclusive access.\r
1152 Currently not implemented.\r
1153 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
1154 RemainingDevicePath is not supported by the driver specified by This.\r
1155**/\r
1156EFI_STATUS\r
1157EFIAPI\r
1158IScsiIp6DriverBindingSupported (\r
1159 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1160 IN EFI_HANDLE ControllerHandle,\r
1161 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
1162 )\r
1163{\r
1164 return IScsiSupported (\r
1165 This,\r
1166 ControllerHandle,\r
1167 RemainingDevicePath,\r
1168 IP_VERSION_6\r
1169 );\r
1170}\r
1171\r
1172/**\r
1173 Starts a device controller or a bus controller.\r
1174\r
1175 The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
1176 As a result, much of the error checking on the parameters to Start() has been moved into this \r
1177 common boot service. It is legal to call Start() from other locations, \r
1178 but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
1179 1. ControllerHandle must be a valid EFI_HANDLE.\r
1180 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
1181 EFI_DEVICE_PATH_PROTOCOL.\r
1182 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
1183 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. \r
1184\r
1185 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
1186 @param[in] ControllerHandle The handle of the controller to start. This handle \r
1187 must support a protocol interface that supplies \r
1188 an I/O abstraction to the driver.\r
1189 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This \r
1190 parameter is ignored by device drivers, and is optional for bus \r
1191 drivers. For a bus driver, if this parameter is NULL, then handles \r
1192 for all the children of Controller are created by this driver. \r
1193 If this parameter is not NULL and the first Device Path Node is \r
1194 not the End of Device Path Node, then only the handle for the \r
1195 child device specified by the first Device Path Node of \r
1196 RemainingDevicePath is created by this driver.\r
1197 If the first Device Path Node of RemainingDevicePath is \r
1198 the End of Device Path Node, no child handle is created by this\r
1199 driver.\r
1200\r
1201 @retval EFI_SUCCESS The device was started.\r
1202 @retval EFI_DEVICE_ERROR The device could not be started due to a device error. Currently not implemented.\r
1203 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
1204 @retval Others The driver failed to start the device.\r
1205\r
1206**/\r
1207EFI_STATUS\r
1208EFIAPI\r
1209IScsiIp6DriverBindingStart (\r
1210 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1211 IN EFI_HANDLE ControllerHandle,\r
1212 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
1213 )\r
1214{\r
1215 EFI_STATUS Status;\r
1216\r
1217 Status = IScsiStart (This->DriverBindingHandle, ControllerHandle, IP_VERSION_6);\r
1218 if (Status == EFI_ALREADY_STARTED) {\r
1219 Status = EFI_SUCCESS;\r
1220 }\r
1221\r
1222 return Status;\r
1223}\r
1224\r
1225/**\r
1226 Stops a device controller or a bus controller.\r
1227 \r
1228 The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). \r
1229 As a result, much of the error checking on the parameters to Stop() has been moved \r
1230 into this common boot service. It is legal to call Stop() from other locations, \r
1231 but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
1232 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
1233 same driver's Start() function.\r
1234 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
1235 EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
1236 Start() function, and the Start() function must have called OpenProtocol() on\r
1237 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
1238 \r
1239 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
1240 @param[in] ControllerHandle A handle to the device being stopped. The handle must \r
1241 support a bus specific I/O protocol for the driver \r
1242 to use to stop the device.\r
1243 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
1244 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL \r
1245 if NumberOfChildren is 0.\r
1246\r
1247 @retval EFI_SUCCESS The device was stopped.\r
1248 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
1249\r
1250**/\r
1251EFI_STATUS\r
1252EFIAPI\r
1253IScsiIp6DriverBindingStop (\r
1254 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1255 IN EFI_HANDLE ControllerHandle,\r
1256 IN UINTN NumberOfChildren,\r
1257 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL\r
1258 )\r
1259{\r
1260 return IScsiStop (\r
1261 This,\r
1262 ControllerHandle,\r
1263 NumberOfChildren,\r
1264 ChildHandleBuffer,\r
1265 IP_VERSION_6\r
1266 );\r
1267}\r
1268\r
1269/**\r
1270 Unload the iSCSI driver.\r
1271\r
1272 @param[in] ImageHandle The handle of the driver image.\r
1273\r
1274 @retval EFI_SUCCESS The driver is unloaded.\r
1275 @retval EFI_DEVICE_ERROR An unexpected error occurred.\r
1276\r
1277**/\r
1278EFI_STATUS\r
1279EFIAPI\r
1280IScsiUnload (\r
1281 IN EFI_HANDLE ImageHandle\r
1282 )\r
1283{\r
1284 EFI_STATUS Status;\r
1285 UINTN DeviceHandleCount;\r
1286 EFI_HANDLE *DeviceHandleBuffer;\r
1287 UINTN Index;\r
1288 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;\r
1289 EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;\r
1290\r
1291 //\r
1292 // Try to disonnect the driver from the devices it's controlling.\r
1293 //\r
1294 Status = gBS->LocateHandleBuffer (\r
1295 AllHandles,\r
1296 NULL,\r
1297 NULL,\r
1298 &DeviceHandleCount,\r
1299 &DeviceHandleBuffer\r
1300 );\r
1301 if (EFI_ERROR (Status)) {\r
1302 return Status;\r
1303 }\r
1304\r
1305 //\r
1306 // Disconnect the iSCSI4 driver from the controlled device.\r
1307 //\r
1308 for (Index = 0; Index < DeviceHandleCount; Index++) {\r
1309 Status = IScsiTestManagedDevice (\r
1310 DeviceHandleBuffer[Index],\r
1311 gIScsiIp4DriverBinding.DriverBindingHandle,\r
1312 &gEfiTcp4ProtocolGuid)\r
1313 ;\r
1314 if (EFI_ERROR (Status)) {\r
1315 continue;\r
1316 }\r
1317 Status = gBS->DisconnectController (\r
1318 DeviceHandleBuffer[Index],\r
1319 gIScsiIp4DriverBinding.DriverBindingHandle,\r
1320 NULL\r
1321 );\r
1322 if (EFI_ERROR (Status)) {\r
1323 goto ON_EXIT;\r
1324 }\r
1325 }\r
1326\r
1327 //\r
1328 // Disconnect the iSCSI6 driver from the controlled device.\r
1329 //\r
1330 for (Index = 0; Index < DeviceHandleCount; Index++) {\r
1331 Status = IScsiTestManagedDevice (\r
1332 DeviceHandleBuffer[Index],\r
1333 gIScsiIp6DriverBinding.DriverBindingHandle,\r
1334 &gEfiTcp6ProtocolGuid\r
1335 );\r
1336 if (EFI_ERROR (Status)) {\r
1337 continue;\r
1338 }\r
1339 Status = gBS->DisconnectController (\r
1340 DeviceHandleBuffer[Index],\r
1341 gIScsiIp6DriverBinding.DriverBindingHandle,\r
1342 NULL\r
1343 );\r
1344 if (EFI_ERROR (Status)) {\r
1345 goto ON_EXIT;\r
1346 }\r
1347 }\r
1348\r
1349 //\r
1350 // Unload the iSCSI configuration form.\r
1351 //\r
1352 Status = IScsiConfigFormUnload (gIScsiIp4DriverBinding.DriverBindingHandle);\r
1353 if (EFI_ERROR (Status)) {\r
1354 goto ON_EXIT;\r
1355 }\r
1356 \r
1357 //\r
1358 // Uninstall the protocols installed by iSCSI driver.\r
1359 //\r
1360 Status = gBS->UninstallMultipleProtocolInterfaces (\r
1361 ImageHandle,\r
1362 &gEfiAuthenticationInfoProtocolGuid,\r
1363 &gIScsiAuthenticationInfo,\r
1364 NULL\r
1365 );\r
1366 if (EFI_ERROR (Status)) {\r
1367 goto ON_EXIT;\r
1368 }\r
1369 \r
1370 if (gIScsiControllerNameTable!= NULL) {\r
1371 Status = FreeUnicodeStringTable (gIScsiControllerNameTable);\r
1372 if (EFI_ERROR (Status)) {\r
1373 goto ON_EXIT;\r
1374 }\r
1375 gIScsiControllerNameTable = NULL;\r
1376 }\r
1377\r
1378 //\r
1379 // Uninstall the ComponentName and ComponentName2 protocol from iSCSI4 driver binding handle\r
1380 // if it has been installed.\r
1381 //\r
1382 Status = gBS->HandleProtocol (\r
1383 gIScsiIp4DriverBinding.DriverBindingHandle,\r
1384 &gEfiComponentNameProtocolGuid,\r
1385 (VOID **) &ComponentName\r
1386 );\r
1387 if (!EFI_ERROR (Status)) {\r
1388 Status = gBS->UninstallMultipleProtocolInterfaces (\r
1389 gIScsiIp4DriverBinding.DriverBindingHandle,\r
1390 &gEfiComponentNameProtocolGuid,\r
1391 ComponentName,\r
1392 NULL\r
1393 );\r
1394 if (EFI_ERROR (Status)) {\r
1395 goto ON_EXIT;\r
1396 }\r
1397 }\r
1398 \r
1399 Status = gBS->HandleProtocol (\r
1400 gIScsiIp4DriverBinding.DriverBindingHandle,\r
1401 &gEfiComponentName2ProtocolGuid,\r
1402 (VOID **) &ComponentName2\r
1403 );\r
1404 if (!EFI_ERROR (Status)) {\r
1405 gBS->UninstallMultipleProtocolInterfaces (\r
1406 gIScsiIp4DriverBinding.DriverBindingHandle,\r
1407 &gEfiComponentName2ProtocolGuid,\r
1408 ComponentName2,\r
1409 NULL\r
1410 );\r
1411 if (EFI_ERROR (Status)) {\r
1412 goto ON_EXIT;\r
1413 }\r
1414 }\r
1415\r
1416 //\r
1417 // Uninstall the ComponentName and ComponentName2 protocol from iSCSI6 driver binding handle\r
1418 // if it has been installed.\r
1419 //\r
1420 Status = gBS->HandleProtocol (\r
1421 gIScsiIp6DriverBinding.DriverBindingHandle,\r
1422 &gEfiComponentNameProtocolGuid,\r
1423 (VOID **) &ComponentName\r
1424 );\r
1425 if (!EFI_ERROR (Status)) {\r
1426 Status = gBS->UninstallMultipleProtocolInterfaces (\r
1427 gIScsiIp6DriverBinding.DriverBindingHandle,\r
1428 &gEfiComponentNameProtocolGuid,\r
1429 ComponentName,\r
1430 NULL\r
1431 );\r
1432 if (EFI_ERROR (Status)) {\r
1433 goto ON_EXIT;\r
1434 }\r
1435 }\r
1436 \r
1437 Status = gBS->HandleProtocol (\r
1438 gIScsiIp6DriverBinding.DriverBindingHandle,\r
1439 &gEfiComponentName2ProtocolGuid,\r
1440 (VOID **) &ComponentName2\r
1441 );\r
1442 if (!EFI_ERROR (Status)) {\r
1443 gBS->UninstallMultipleProtocolInterfaces (\r
1444 gIScsiIp6DriverBinding.DriverBindingHandle,\r
1445 &gEfiComponentName2ProtocolGuid,\r
1446 ComponentName2,\r
1447 NULL\r
1448 );\r
1449 if (EFI_ERROR (Status)) {\r
1450 goto ON_EXIT;\r
1451 }\r
1452 }\r
1453\r
1454 //\r
1455 // Uninstall the IScsiInitiatorNameProtocol and all the driver binding protocols.\r
1456 //\r
1457 Status = gBS->UninstallMultipleProtocolInterfaces (\r
1458 gIScsiIp4DriverBinding.DriverBindingHandle,\r
1459 &gEfiDriverBindingProtocolGuid,\r
1460 &gIScsiIp4DriverBinding,\r
1461 &gEfiIScsiInitiatorNameProtocolGuid,\r
1462 &gIScsiInitiatorName,\r
1463 NULL\r
1464 );\r
1465 if (EFI_ERROR (Status)) {\r
1466 goto ON_EXIT;\r
1467 }\r
1468\r
1469 Status = gBS->UninstallMultipleProtocolInterfaces (\r
1470 gIScsiIp6DriverBinding.DriverBindingHandle,\r
1471 &gEfiDriverBindingProtocolGuid,\r
1472 &gIScsiIp6DriverBinding,\r
1473 NULL\r
1474 );\r
1475\r
1476ON_EXIT:\r
1477\r
1478 if (DeviceHandleBuffer != NULL) {\r
1479 FreePool (DeviceHandleBuffer);\r
1480 }\r
1481 \r
1482 return Status;\r
1483}\r
1484\r
1485/**\r
1486 This is the declaration of an EFI image entry point. This entry point is\r
1487 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including\r
1488 both device drivers and bus drivers.\r
1489 \r
1490 The entry point for iSCSI driver which initializes the global variables and\r
1491 installs the driver binding, component name protocol, iSCSI initiator name\r
1492 protocol and Authentication Info protocol on its image.\r
1493 \r
1494 @param[in] ImageHandle The firmware allocated handle for the UEFI image.\r
1495 @param[in] SystemTable A pointer to the EFI System Table.\r
1496\r
1497 @retval EFI_SUCCESS The operation completed successfully.\r
1498 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
1499\r
1500**/\r
1501EFI_STATUS\r
1502EFIAPI\r
1503IScsiDriverEntryPoint (\r
1504 IN EFI_HANDLE ImageHandle,\r
1505 IN EFI_SYSTEM_TABLE *SystemTable\r
1506 )\r
1507{\r
1508 EFI_STATUS Status;\r
1509 EFI_ISCSI_INITIATOR_NAME_PROTOCOL *IScsiInitiatorName;\r
1510 EFI_AUTHENTICATION_INFO_PROTOCOL *AuthenticationInfo;\r
1511\r
1512 //\r
1513 // There should be only one EFI_ISCSI_INITIATOR_NAME_PROTOCOL.\r
1514 //\r
1515 Status = gBS->LocateProtocol (\r
1516 &gEfiIScsiInitiatorNameProtocolGuid,\r
1517 NULL,\r
1518 (VOID **) &IScsiInitiatorName\r
1519 );\r
1520 if (!EFI_ERROR (Status)) {\r
1521 return EFI_ACCESS_DENIED;\r
1522 }\r
1523\r
1524 //\r
1525 // Initialize the EFI Driver Library.\r
1526 //\r
1527 Status = EfiLibInstallDriverBindingComponentName2 (\r
1528 ImageHandle,\r
1529 SystemTable,\r
1530 &gIScsiIp4DriverBinding,\r
1531 ImageHandle,\r
1532 &gIScsiComponentName,\r
1533 &gIScsiComponentName2\r
1534 );\r
1535 if (EFI_ERROR (Status)) {\r
1536 return Status;\r
1537 }\r
1538\r
1539 Status = EfiLibInstallDriverBindingComponentName2 (\r
1540 ImageHandle,\r
1541 SystemTable,\r
1542 &gIScsiIp6DriverBinding,\r
1543 NULL,\r
1544 &gIScsiComponentName,\r
1545 &gIScsiComponentName2\r
1546 );\r
1547 if (EFI_ERROR (Status)) {\r
1548 goto Error1;\r
1549 }\r
1550 \r
1551 //\r
1552 // Install the iSCSI Initiator Name Protocol.\r
1553 //\r
1554 Status = gBS->InstallProtocolInterface (\r
1555 &ImageHandle,\r
1556 &gEfiIScsiInitiatorNameProtocolGuid,\r
1557 EFI_NATIVE_INTERFACE,\r
1558 &gIScsiInitiatorName\r
1559 );\r
1560 if (EFI_ERROR (Status)) {\r
1561 goto Error2;\r
1562 } \r
1563\r
1564 //\r
1565 // Create the private data structures.\r
1566 //\r
1567 mPrivate = AllocateZeroPool (sizeof (ISCSI_PRIVATE_DATA));\r
1568 if (mPrivate == NULL) {\r
1569 Status = EFI_OUT_OF_RESOURCES;\r
1570 goto Error3;\r
1571 }\r
1572\r
1573 InitializeListHead (&mPrivate->NicInfoList);\r
1574 InitializeListHead (&mPrivate->AttemptConfigs);\r
1575\r
1576 //\r
1577 // Initialize the configuration form of iSCSI.\r
1578 //\r
1579 Status = IScsiConfigFormInit (gIScsiIp4DriverBinding.DriverBindingHandle);\r
1580 if (EFI_ERROR (Status)) {\r
1581 goto Error4;\r
1582 }\r
1583\r
1584 //\r
1585 // There should be only one EFI_AUTHENTICATION_INFO_PROTOCOL. If already exists,\r
1586 // do not produce the protocol instance.\r
1587 //\r
1588 Status = gBS->LocateProtocol (\r
1589 &gEfiAuthenticationInfoProtocolGuid,\r
1590 NULL,\r
1591 (VOID **) &AuthenticationInfo\r
1592 );\r
1593 if (Status == EFI_NOT_FOUND) {\r
1594 Status = gBS->InstallProtocolInterface (\r
1595 &ImageHandle,\r
1596 &gEfiAuthenticationInfoProtocolGuid,\r
1597 EFI_NATIVE_INTERFACE,\r
1598 &gIScsiAuthenticationInfo\r
1599 );\r
1600 if (EFI_ERROR (Status)) {\r
1601 goto Error5;\r
1602 } \r
1603 }\r
1604\r
1605 return EFI_SUCCESS;\r
1606\r
1607Error5:\r
1608 IScsiConfigFormUnload (gIScsiIp4DriverBinding.DriverBindingHandle);\r
1609\r
1610Error4:\r
1611 FreePool (mPrivate);\r
1612\r
1613Error3:\r
1614 gBS->UninstallMultipleProtocolInterfaces (\r
1615 ImageHandle,\r
1616 &gEfiIScsiInitiatorNameProtocolGuid,\r
1617 &gIScsiInitiatorName,\r
1618 NULL\r
1619 );\r
1620\r
1621Error2:\r
1622 gBS->UninstallMultipleProtocolInterfaces (\r
1623 gIScsiIp6DriverBinding.DriverBindingHandle,\r
1624 &gEfiDriverBindingProtocolGuid,\r
1625 &gIScsiIp6DriverBinding,\r
1626 &gEfiComponentName2ProtocolGuid,\r
1627 &gIScsiComponentName2,\r
1628 &gEfiComponentNameProtocolGuid,\r
1629 &gIScsiComponentName,\r
1630 NULL\r
1631 );\r
1632\r
1633Error1:\r
1634 gBS->UninstallMultipleProtocolInterfaces (\r
1635 ImageHandle,\r
1636 &gEfiDriverBindingProtocolGuid,\r
1637 &gIScsiIp4DriverBinding,\r
1638 &gEfiComponentName2ProtocolGuid,\r
1639 &gIScsiComponentName2,\r
1640 &gEfiComponentNameProtocolGuid,\r
1641 &gIScsiComponentName,\r
1642 NULL\r
1643 );\r
1644\r
1645 return Status;\r
1646}\r
1647\r