]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/IScsiDxe/IScsiDriver.c
Clean up the private GUID definition in module Level.
[mirror_edk2.git] / NetworkPkg / IScsiDxe / IScsiDriver.c
1 /** @file
2 The entry point of IScsi driver.
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_DRIVER_BINDING_PROTOCOL gIScsiDriverBinding = {
18 IScsiDriverBindingSupported,
19 IScsiDriverBindingStart,
20 IScsiDriverBindingStop,
21 0xa,
22 NULL,
23 NULL
24 };
25
26 EFI_GUID mIScsiV4PrivateGuid = ISCSI_V4_PRIVATE_GUID;
27 EFI_GUID mIScsiV6PrivateGuid = ISCSI_V6_PRIVATE_GUID;
28 ISCSI_PRIVATE_DATA *mPrivate = NULL;
29
30 /**
31 Tests to see if this driver supports the RemainingDevicePath.
32
33 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
34 parameter is ignored by device drivers, and is optional for bus
35 drivers. For bus drivers, if this parameter is not NULL, then
36 the bus driver must determine if the bus controller specified
37 by ControllerHandle and the child controller specified
38 by RemainingDevicePath are both supported by this
39 bus driver.
40
41 @retval EFI_SUCCESS The RemainingDevicePath is supported or NULL.
42 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
43 RemainingDevicePath is not supported by the driver specified by This.
44 **/
45 EFI_STATUS
46 IScsiIsDevicePathSupported (
47 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
48 )
49 {
50 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
51
52 CurrentDevicePath = RemainingDevicePath;
53 if (CurrentDevicePath != NULL) {
54 while (!IsDevicePathEnd (CurrentDevicePath)) {
55 if ((CurrentDevicePath->Type == MESSAGING_DEVICE_PATH) && (CurrentDevicePath->SubType == MSG_ISCSI_DP)) {
56 return EFI_SUCCESS;
57 }
58
59 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
60 }
61
62 return EFI_UNSUPPORTED;
63 }
64
65 return EFI_SUCCESS;
66 }
67
68
69 /**
70 Tests to see if this driver supports a given controller. If a child device is provided,
71 it further tests to see if this driver supports creating a handle for the specified child device.
72
73 This function checks to see if the driver specified by This supports the device specified by
74 ControllerHandle. Drivers typically use the device path attached to
75 ControllerHandle and/or the services from the bus I/O abstraction attached to
76 ControllerHandle to determine if the driver supports ControllerHandle. This function
77 may be called many times during platform initialization. In order to reduce boot times, the tests
78 performed by this function must be very small and take as little time as possible to execute. This
79 function must not change the state of any hardware devices, and this function must be aware that the
80 device specified by ControllerHandle may already be managed by the same driver or a
81 different driver. This function must match its calls to AllocatePages() with FreePages(),
82 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
83 Since ControllerHandle may have been previously started by the same driver, if a protocol is
84 already in the opened state, then it must not be closed with CloseProtocol(). This is required
85 to guarantee the state of ControllerHandle is not modified by this function.
86
87 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
88 @param[in] ControllerHandle The handle of the controller to test. This handle
89 must support a protocol interface that supplies
90 an I/O abstraction to the driver.
91 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
92 parameter is ignored by device drivers, and is optional for bus
93 drivers. For bus drivers, if this parameter is not NULL, then
94 the bus driver must determine if the bus controller specified
95 by ControllerHandle and the child controller specified
96 by RemainingDevicePath are both supported by this
97 bus driver.
98
99 @retval EFI_SUCCESS The device specified by ControllerHandle and
100 RemainingDevicePath is supported by the driver specified by This.
101 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
102 RemainingDevicePath is already being managed by the driver
103 specified by This.
104 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
105 RemainingDevicePath is already being managed by a different
106 driver or an application that requires exclusive access.
107 Currently not implemented.
108 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
109 RemainingDevicePath is not supported by the driver specified by This.
110 **/
111 EFI_STATUS
112 EFIAPI
113 IScsiDriverBindingSupported (
114 IN EFI_DRIVER_BINDING_PROTOCOL *This,
115 IN EFI_HANDLE ControllerHandle,
116 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
117 )
118 {
119 EFI_STATUS Status;
120 BOOLEAN IsIscsi4Started;
121
122 Status = gBS->OpenProtocol (
123 ControllerHandle,
124 &mIScsiV4PrivateGuid,
125 NULL,
126 This->DriverBindingHandle,
127 ControllerHandle,
128 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
129 );
130 if (!EFI_ERROR (Status)) {
131 IsIscsi4Started = TRUE;
132 } else {
133 Status = gBS->OpenProtocol (
134 ControllerHandle,
135 &gEfiTcp4ServiceBindingProtocolGuid,
136 NULL,
137 This->DriverBindingHandle,
138 ControllerHandle,
139 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
140 );
141 if (!EFI_ERROR (Status)) {
142 Status = IScsiIsDevicePathSupported (RemainingDevicePath);
143 if (!EFI_ERROR (Status)) {
144 return EFI_SUCCESS;
145 }
146 }
147
148 IsIscsi4Started = FALSE;
149 }
150
151 Status = gBS->OpenProtocol (
152 ControllerHandle,
153 &mIScsiV6PrivateGuid,
154 NULL,
155 This->DriverBindingHandle,
156 ControllerHandle,
157 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
158 );
159 if (!EFI_ERROR (Status)) {
160 if (IsIscsi4Started) {
161 return EFI_ALREADY_STARTED;
162 }
163 } else {
164 Status = gBS->OpenProtocol (
165 ControllerHandle,
166 &gEfiTcp6ServiceBindingProtocolGuid,
167 NULL,
168 This->DriverBindingHandle,
169 ControllerHandle,
170 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
171 );
172 if (!EFI_ERROR (Status)) {
173 Status = IScsiIsDevicePathSupported (RemainingDevicePath);
174 if (!EFI_ERROR (Status)) {
175 return EFI_SUCCESS;
176 }
177 }
178 }
179
180 return EFI_UNSUPPORTED;
181 }
182
183
184 /**
185 Start to manage the controller. This is the worker function for
186 IScsiDriverBindingStart.
187
188 @param[in] Image Handle of the image.
189 @param[in] ControllerHandle Handle of the controller.
190 @param[in] IpVersion Ip4 or Ip6
191
192 @retval EFI_SUCCES This driver supports this device.
193 @retval EFI_ALREADY_STARTED This driver is already running on this device.
194 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
195 @retval EFI_NOT_FOUND There is no sufficient information to establish
196 the iScsi session.
197 @retval EFI_DEVICE_ERROR Failed to get TCP connection device path.
198
199 **/
200 EFI_STATUS
201 IScsiStart (
202 IN EFI_HANDLE Image,
203 IN EFI_HANDLE ControllerHandle,
204 IN UINT8 IpVersion
205 )
206 {
207 EFI_STATUS Status;
208 ISCSI_DRIVER_DATA *Private;
209 LIST_ENTRY *Entry;
210 LIST_ENTRY *NextEntry;
211 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
212 ISCSI_SESSION *Session;
213 UINT8 Index;
214 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExistIScsiExtScsiPassThru;
215 ISCSI_DRIVER_DATA *ExistPrivate;
216 UINT8 *AttemptConfigOrder;
217 UINTN AttemptConfigOrderSize;
218 UINT8 BootSelected;
219 EFI_HANDLE *HandleBuffer;
220 UINTN NumberOfHandles;
221 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
222 EFI_GUID *IScsiPrivateGuid;
223 EFI_GUID *TcpServiceBindingGuid;
224 CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN];
225 BOOLEAN NeedUpdate;
226 VOID *Interface;
227 EFI_GUID *ProtocolGuid;
228
229 //
230 // Test to see if iSCSI driver supports the given controller.
231 //
232
233 if (IpVersion == IP_VERSION_4) {
234 IScsiPrivateGuid = &mIScsiV4PrivateGuid;
235 TcpServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;
236 ProtocolGuid = &gEfiTcp4ProtocolGuid;
237 } else if (IpVersion == IP_VERSION_6) {
238 IScsiPrivateGuid = &mIScsiV6PrivateGuid;
239 TcpServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;
240 ProtocolGuid = &gEfiTcp6ProtocolGuid;
241 } else {
242 return EFI_INVALID_PARAMETER;
243 }
244
245 Status = gBS->OpenProtocol (
246 ControllerHandle,
247 IScsiPrivateGuid,
248 NULL,
249 Image,
250 ControllerHandle,
251 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
252 );
253 if (!EFI_ERROR (Status)) {
254 return EFI_ALREADY_STARTED;
255 }
256
257 Status = gBS->OpenProtocol (
258 ControllerHandle,
259 TcpServiceBindingGuid,
260 NULL,
261 Image,
262 ControllerHandle,
263 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
264 );
265 if (EFI_ERROR (Status)) {
266 return EFI_UNSUPPORTED;
267 }
268
269 //
270 // Record the incoming NIC info.
271 //
272 Status = IScsiAddNic (ControllerHandle);
273 if (EFI_ERROR (Status)) {
274 return Status;
275 }
276
277 //
278 // Create the instance private data.
279 //
280 Private = IScsiCreateDriverData (Image, ControllerHandle);
281 if (Private == NULL) {
282 return EFI_OUT_OF_RESOURCES;
283 }
284
285 //
286 // Create a underlayer child instance, but not need to configure it. Just open ChildHandle
287 // via BY_DRIVER. That is, establishing the relationship between ControllerHandle and ChildHandle.
288 // Therefore, when DisconnectController(), especially VLAN virtual controller handle,
289 // IScsiDriverBindingStop() will be called.
290 //
291 Status = NetLibCreateServiceChild (
292 ControllerHandle,
293 Image,
294 TcpServiceBindingGuid,
295 &Private->ChildHandle
296 );
297
298 if (EFI_ERROR (Status)) {
299 goto ON_ERROR;
300 }
301
302 Status = gBS->OpenProtocol (
303 Private->ChildHandle,
304 ProtocolGuid,
305 &Interface,
306 Image,
307 ControllerHandle,
308 EFI_OPEN_PROTOCOL_BY_DRIVER
309 );
310
311 if (EFI_ERROR (Status)) {
312 goto ON_ERROR;
313 }
314
315 //
316 // Always install private protocol no matter what happens later. We need to
317 // keep the relationship between ControllerHandle and ChildHandle.
318 //
319 Status = gBS->InstallProtocolInterface (
320 &ControllerHandle,
321 IScsiPrivateGuid,
322 EFI_NATIVE_INTERFACE,
323 &Private->IScsiIdentifier
324 );
325 if (EFI_ERROR (Status)) {
326 goto ON_ERROR;
327 }
328
329 if (IpVersion == IP_VERSION_4) {
330 mPrivate->Ipv6Flag = FALSE;
331 } else {
332 mPrivate->Ipv6Flag = TRUE;
333 }
334
335 //
336 // Get the current iSCSI configuration data.
337 //
338 Status = IScsiGetConfigData (Private);
339 if (EFI_ERROR (Status)) {
340 goto ON_ERROR;
341 }
342
343 //
344 // If there is already a successul attempt, check whether this attempt is the
345 // first "enabled for MPIO" attempt. If not, still try the first attempt.
346 // In single path mode, try all attempts.
347 //
348 ExistPrivate = NULL;
349 Status = EFI_NOT_FOUND;
350
351 if (mPrivate->OneSessionEstablished && mPrivate->EnableMpio) {
352 AttemptConfigData = NULL;
353 NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {
354 AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
355 if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
356 break;
357 }
358 }
359
360 if (AttemptConfigData == NULL) {
361 goto ON_ERROR;
362 }
363
364 if (AttemptConfigData->AttemptConfigIndex == mPrivate->BootSelectedIndex) {
365 goto ON_EXIT;
366 }
367
368 //
369 // Uninstall the original ExtScsiPassThru first.
370 //
371
372 //
373 // Locate all ExtScsiPassThru protocol instances.
374 //
375 Status = gBS->LocateHandleBuffer (
376 ByProtocol,
377 &gEfiExtScsiPassThruProtocolGuid,
378 NULL,
379 &NumberOfHandles,
380 &HandleBuffer
381 );
382 if (EFI_ERROR (Status)) {
383 goto ON_ERROR;
384 }
385
386 //
387 // Find ExtScsiPassThru protocol instance produced by this driver.
388 //
389 ExistIScsiExtScsiPassThru = NULL;
390 for (Index = 0; Index < NumberOfHandles && ExistIScsiExtScsiPassThru == NULL; Index++) {
391 Status = gBS->HandleProtocol (
392 HandleBuffer[Index],
393 &gEfiDevicePathProtocolGuid,
394 (VOID **) &DevicePath
395 );
396 if (EFI_ERROR (Status)) {
397 continue;
398 }
399
400 while (!IsDevicePathEnd (DevicePath)) {
401 if ((DevicePath->Type == MESSAGING_DEVICE_PATH) && (DevicePath->SubType == MSG_MAC_ADDR_DP)) {
402 //
403 // Get the ExtScsiPassThru protocol instance.
404 //
405 Status = gBS->HandleProtocol (
406 HandleBuffer[Index],
407 &gEfiExtScsiPassThruProtocolGuid,
408 (VOID **) &ExistIScsiExtScsiPassThru
409 );
410 ASSERT_EFI_ERROR (Status);
411 break;
412 }
413
414 DevicePath = NextDevicePathNode (DevicePath);
415 }
416 }
417
418 FreePool (HandleBuffer);
419
420 if (ExistIScsiExtScsiPassThru == NULL) {
421 Status = EFI_NOT_FOUND;
422 goto ON_ERROR;
423 }
424
425 ExistPrivate = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (ExistIScsiExtScsiPassThru);
426
427 Status = gBS->UninstallProtocolInterface (
428 ExistPrivate->ExtScsiPassThruHandle,
429 &gEfiExtScsiPassThruProtocolGuid,
430 &ExistPrivate->IScsiExtScsiPassThru
431 );
432 if (EFI_ERROR (Status)) {
433 goto ON_ERROR;
434 }
435 }
436
437 //
438 // Install the Ext SCSI PASS THRU protocol.
439 //
440 Status = gBS->InstallProtocolInterface (
441 &Private->ExtScsiPassThruHandle,
442 &gEfiExtScsiPassThruProtocolGuid,
443 EFI_NATIVE_INTERFACE,
444 &Private->IScsiExtScsiPassThru
445 );
446 if (EFI_ERROR (Status)) {
447 goto ON_ERROR;
448 }
449
450 BootSelected = 0;
451
452 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mPrivate->AttemptConfigs) {
453 AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
454 //
455 // Don't process the attempt that does not associate with the current NIC or
456 // this attempt is disabled or established.
457 //
458 if (AttemptConfigData->NicIndex != mPrivate->CurrentNic ||
459 AttemptConfigData->SessionConfigData.Enabled == ISCSI_DISABLED ||
460 AttemptConfigData->ValidPath) {
461 continue;
462 }
463
464 //
465 // In multipath mode, don't process attempts configured for single path.
466 // In default single path mode, don't process attempts configured for multipath.
467 //
468 if ((mPrivate->EnableMpio &&
469 AttemptConfigData->SessionConfigData.Enabled != ISCSI_ENABLED_FOR_MPIO) ||
470 (!mPrivate->EnableMpio &&
471 AttemptConfigData->SessionConfigData.Enabled != ISCSI_ENABLED)) {
472 continue;
473 }
474
475 //
476 // Don't process the attempt that fails to get the init/target information from DHCP.
477 //
478 if (AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp &&
479 !AttemptConfigData->DhcpSuccess) {
480 if (!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount > 0) {
481 mPrivate->ValidSinglePathCount--;
482 }
483 continue;
484 }
485
486 //
487 // Don't process the autoconfigure path if it is already established.
488 //
489 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&
490 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_SUCCESS) {
491 continue;
492 }
493
494 //
495 // Don't process the attempt if its IP mode is not in the current IP version.
496 //
497 if (!mPrivate->Ipv6Flag) {
498 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6) {
499 continue;
500 }
501 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&
502 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6) {
503 continue;
504 }
505 } else {
506 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4) {
507 continue;
508 }
509 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&
510 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4) {
511 continue;
512 }
513 }
514
515 //
516 // Fill in the Session and init it.
517 //
518 Session = (ISCSI_SESSION *) AllocateZeroPool (sizeof (ISCSI_SESSION));
519 if (Session == NULL) {
520 Status = EFI_OUT_OF_RESOURCES;
521 goto ON_ERROR;
522 }
523
524 Session->Private = Private;
525 Session->ConfigData = AttemptConfigData;
526 Session->AuthType = AttemptConfigData->AuthenticationType;
527
528 AsciiStrToUnicodeStr (AttemptConfigData->MacString, MacString);
529 UnicodeSPrint (
530 mPrivate->PortString,
531 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
532 L"%s%d",
533 MacString,
534 (UINTN) AttemptConfigData->AttemptConfigIndex
535 );
536
537 if (Session->AuthType == ISCSI_AUTH_TYPE_CHAP) {
538 Session->AuthData.CHAP.AuthConfig = &AttemptConfigData->AuthConfigData.CHAP;
539 }
540
541 IScsiSessionInit (Session, FALSE);
542
543 //
544 // Try to login and create an iSCSI session according to the configuration.
545 //
546 Status = IScsiSessionLogin (Session);
547 if (Status == EFI_MEDIA_CHANGED) {
548 //
549 // The specified target is not available, and the redirection information is
550 // received. Login the session again with the updated target address.
551 //
552 Status = IScsiSessionLogin (Session);
553 } else if (Status == EFI_NOT_READY) {
554 Status = IScsiSessionReLogin (Session);
555 }
556
557 if (EFI_ERROR (Status)) {
558 //
559 // In Single path mode, only the successful attempt will be recorded in iBFT;
560 // in multi-path mode, all the attempt entries in MPIO will be recorded in iBFT.
561 //
562 if (!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount > 0) {
563 mPrivate->ValidSinglePathCount--;
564 }
565
566 FreePool (Session);
567
568 } else {
569 AttemptConfigData->ValidPath = TRUE;
570
571 //
572 // Do not record the attempt in iBFT if it login with KRB5.
573 // TODO: record KRB5 attempt information in the iSCSI device path.
574 //
575 if (Session->AuthType == ISCSI_AUTH_TYPE_KRB) {
576 if (!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount > 0) {
577 mPrivate->ValidSinglePathCount--;
578 }
579
580 AttemptConfigData->ValidiBFTPath = FALSE;
581 } else {
582 AttemptConfigData->ValidiBFTPath = TRUE;
583 }
584
585 //
586 // IScsi session success. Update the attempt state to NVR.
587 //
588 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {
589 AttemptConfigData->AutoConfigureMode = IP_MODE_AUTOCONFIG_SUCCESS;
590 }
591
592 gRT->SetVariable (
593 mPrivate->PortString,
594 &gEfiIScsiInitiatorNameProtocolGuid,
595 ISCSI_CONFIG_VAR_ATTR,
596 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
597 AttemptConfigData
598 );
599
600 //
601 // Select the first login session. Abort others.
602 //
603 if (Private->Session == NULL) {
604 Private->Session = Session;
605 BootSelected = AttemptConfigData->AttemptConfigIndex;
606 //
607 // Don't validate other attempt in multipath mode if one is success.
608 //
609 if (mPrivate->EnableMpio) {
610 break;
611 }
612 } else {
613 IScsiSessionAbort (Session);
614 FreePool (Session);
615 }
616 }
617 }
618
619 //
620 // All attempts configured for this driver instance are not valid.
621 //
622 if (Private->Session == NULL) {
623 Status = gBS->UninstallProtocolInterface (
624 Private->ExtScsiPassThruHandle,
625 &gEfiExtScsiPassThruProtocolGuid,
626 &Private->IScsiExtScsiPassThru
627 );
628 ASSERT_EFI_ERROR (Status);
629 Private->ExtScsiPassThruHandle = NULL;
630
631 //
632 // Reinstall the original ExtScsiPassThru back.
633 //
634 if (mPrivate->OneSessionEstablished && ExistPrivate != NULL) {
635 Status = gBS->InstallProtocolInterface (
636 &ExistPrivate->ExtScsiPassThruHandle,
637 &gEfiExtScsiPassThruProtocolGuid,
638 EFI_NATIVE_INTERFACE,
639 &ExistPrivate->IScsiExtScsiPassThru
640 );
641 if (EFI_ERROR (Status)) {
642 goto ON_ERROR;
643 }
644
645 goto ON_EXIT;
646 }
647
648 Status = EFI_NOT_FOUND;
649
650 goto ON_ERROR;
651 }
652
653 NeedUpdate = TRUE;
654 //
655 // More than one attempt successes.
656 //
657 if (Private->Session != NULL && mPrivate->OneSessionEstablished) {
658
659 AttemptConfigOrder = IScsiGetVariableAndSize (
660 L"AttemptOrder",
661 &gIScsiConfigGuid,
662 &AttemptConfigOrderSize
663 );
664 ASSERT (AttemptConfigOrder != NULL);
665 for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
666 if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex ||
667 AttemptConfigOrder[Index] == BootSelected) {
668 break;
669 }
670 }
671
672 if (mPrivate->EnableMpio) {
673 //
674 // Use the attempt in earlier order. Abort the later one in MPIO.
675 //
676 if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex) {
677 IScsiSessionAbort (Private->Session);
678 FreePool (Private->Session);
679 Private->Session = NULL;
680 gBS->UninstallProtocolInterface (
681 Private->ExtScsiPassThruHandle,
682 &gEfiExtScsiPassThruProtocolGuid,
683 &Private->IScsiExtScsiPassThru
684 );
685 Private->ExtScsiPassThruHandle = NULL;
686
687 //
688 // Reinstall the original ExtScsiPassThru back.
689 //
690 Status = gBS->InstallProtocolInterface (
691 &ExistPrivate->ExtScsiPassThruHandle,
692 &gEfiExtScsiPassThruProtocolGuid,
693 EFI_NATIVE_INTERFACE,
694 &ExistPrivate->IScsiExtScsiPassThru
695 );
696 if (EFI_ERROR (Status)) {
697 goto ON_ERROR;
698 }
699
700 goto ON_EXIT;
701 } else {
702 ASSERT (AttemptConfigOrder[Index] == BootSelected);
703 mPrivate->BootSelectedIndex = BootSelected;
704 //
705 // Clear the resource in ExistPrivate.
706 //
707 gBS->UninstallProtocolInterface (
708 ExistPrivate->Controller,
709 IScsiPrivateGuid,
710 &ExistPrivate->IScsiIdentifier
711 );
712
713 IScsiRemoveNic (ExistPrivate->Controller);
714 if (ExistPrivate->Session != NULL) {
715 IScsiSessionAbort (ExistPrivate->Session);
716 }
717
718 IScsiCleanDriverData (ExistPrivate);
719 }
720 } else {
721 //
722 // Use the attempt in earlier order as boot selected in single path mode.
723 //
724 if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex) {
725 NeedUpdate = FALSE;
726 }
727 }
728
729 }
730
731 if (NeedUpdate) {
732 mPrivate->OneSessionEstablished = TRUE;
733 mPrivate->BootSelectedIndex = BootSelected;
734 }
735
736 //
737 // Duplicate the Session's tcp connection device path. The source port field
738 // will be set to zero as one iSCSI session is comprised of several iSCSI
739 // connections.
740 //
741 Private->DevicePath = IScsiGetTcpConnDevicePath (Private->Session);
742 if (Private->DevicePath == NULL) {
743 Status = EFI_DEVICE_ERROR;
744 goto ON_ERROR;
745 }
746 //
747 // Install the updated device path onto the ExtScsiPassThruHandle.
748 //
749 Status = gBS->InstallProtocolInterface (
750 &Private->ExtScsiPassThruHandle,
751 &gEfiDevicePathProtocolGuid,
752 EFI_NATIVE_INTERFACE,
753 Private->DevicePath
754 );
755 if (EFI_ERROR (Status)) {
756 goto ON_ERROR;
757 }
758
759 ON_EXIT:
760
761 //
762 // Update/Publish the iSCSI Boot Firmware Table.
763 //
764 if (mPrivate->BootSelectedIndex != 0) {
765 IScsiPublishIbft ();
766 }
767
768 return EFI_SUCCESS;
769
770 ON_ERROR:
771
772 if (Private->Session != NULL) {
773 IScsiSessionAbort (Private->Session);
774 }
775
776 return Status;
777 }
778
779 /**
780 Starts a device controller or a bus controller.
781
782 The Start() function is designed to be invoked from the EFI boot service ConnectController().
783 As a result, much of the error checking on the parameters to Start() has been moved into this
784 common boot service. It is legal to call Start() from other locations,
785 but the following calling restrictions must be followed or the system behavior will not be deterministic.
786 1. ControllerHandle must be a valid EFI_HANDLE.
787 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
788 EFI_DEVICE_PATH_PROTOCOL.
789 3. Prior to calling Start(), the Supported() function for the driver specified by This must
790 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
791
792 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
793 @param[in] ControllerHandle The handle of the controller to start. This handle
794 must support a protocol interface that supplies
795 an I/O abstraction to the driver.
796 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
797 parameter is ignored by device drivers, and is optional for bus
798 drivers. For a bus driver, if this parameter is NULL, then handles
799 for all the children of Controller are created by this driver.
800 If this parameter is not NULL and the first Device Path Node is
801 not the End of Device Path Node, then only the handle for the
802 child device specified by the first Device Path Node of
803 RemainingDevicePath is created by this driver.
804 If the first Device Path Node of RemainingDevicePath is
805 the End of Device Path Node, no child handle is created by this
806 driver.
807
808 @retval EFI_SUCCESS The device was started.
809 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
810 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
811 @retval Others The driver failed to start the device.
812
813 **/
814 EFI_STATUS
815 EFIAPI
816 IScsiDriverBindingStart (
817 IN EFI_DRIVER_BINDING_PROTOCOL *This,
818 IN EFI_HANDLE ControllerHandle,
819 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
820 )
821 {
822 EFI_STATUS V4Status;
823 EFI_STATUS V6Status;
824
825 V4Status = IScsiStart (This->DriverBindingHandle, ControllerHandle, IP_VERSION_4);
826 if (V4Status == EFI_ALREADY_STARTED) {
827 V4Status = EFI_SUCCESS;
828 }
829
830 V6Status = IScsiStart (This->DriverBindingHandle, ControllerHandle, IP_VERSION_6);
831 if (V6Status == EFI_ALREADY_STARTED) {
832 V6Status = EFI_SUCCESS;
833 }
834
835 if (!EFI_ERROR (V4Status) || !EFI_ERROR (V6Status)) {
836 return EFI_SUCCESS;
837 } else if (EFI_ERROR (V4Status)) {
838 return V4Status;
839 } else {
840 return V6Status;
841 }
842 }
843
844 /**
845 Stops a device controller or a bus controller.
846
847 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
848 As a result, much of the error checking on the parameters to Stop() has been moved
849 into this common boot service. It is legal to call Stop() from other locations,
850 but the following calling restrictions must be followed or the system behavior will not be deterministic.
851 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
852 same driver's Start() function.
853 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
854 EFI_HANDLE. In addition, all of these handles must have been created in this driver's
855 Start() function, and the Start() function must have called OpenProtocol() on
856 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
857
858 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
859 @param[in] ControllerHandle A handle to the device being stopped. The handle must
860 support a bus specific I/O protocol for the driver
861 to use to stop the device.
862 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
863 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
864 if NumberOfChildren is 0.
865
866 @retval EFI_SUCCESS The device was stopped.
867 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
868
869 **/
870 EFI_STATUS
871 EFIAPI
872 IScsiDriverBindingStop (
873 IN EFI_DRIVER_BINDING_PROTOCOL *This,
874 IN EFI_HANDLE ControllerHandle,
875 IN UINTN NumberOfChildren,
876 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
877 )
878 {
879 EFI_HANDLE IScsiController;
880 EFI_STATUS Status;
881 ISCSI_PRIVATE_PROTOCOL *IScsiIdentifier;
882 ISCSI_DRIVER_DATA *Private;
883 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
884 ISCSI_CONNECTION *Conn;
885 EFI_GUID *ProtocolGuid;
886 EFI_GUID *TcpServiceBindingGuid;
887 EFI_GUID *TcpProtocolGuid;
888
889
890 if (NumberOfChildren != 0) {
891 //
892 // We should have only one child.
893 //
894 Status = gBS->OpenProtocol (
895 ChildHandleBuffer[0],
896 &gEfiExtScsiPassThruProtocolGuid,
897 (VOID **) &PassThru,
898 This->DriverBindingHandle,
899 ControllerHandle,
900 EFI_OPEN_PROTOCOL_GET_PROTOCOL
901 );
902 if (EFI_ERROR (Status)) {
903 return EFI_DEVICE_ERROR;
904 }
905
906 Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (PassThru);
907 Conn = NET_LIST_HEAD (&Private->Session->Conns, ISCSI_CONNECTION, Link);
908
909 //
910 // Previously the TCP protocol is opened BY_CHILD_CONTROLLER. Just close
911 // the protocol here, but do not uninstall the device path protocol and
912 // EXT SCSI PASS THRU protocol installed on ExtScsiPassThruHandle.
913 //
914 if (!Conn->Ipv6Flag) {
915 ProtocolGuid = &gEfiTcp4ProtocolGuid;
916 } else {
917 ProtocolGuid = &gEfiTcp6ProtocolGuid;
918 }
919
920 gBS->CloseProtocol (
921 Conn->TcpIo.Handle,
922 ProtocolGuid,
923 Private->Image,
924 Private->ExtScsiPassThruHandle
925 );
926
927 return EFI_SUCCESS;
928 }
929 //
930 // Get the handle of the controller we are controling.
931 //
932 IScsiController = NetLibGetNicHandle (ControllerHandle, &gEfiTcp4ProtocolGuid);
933 if (IScsiController != NULL) {
934 ProtocolGuid = &mIScsiV4PrivateGuid;
935 TcpProtocolGuid = &gEfiTcp4ProtocolGuid;
936 TcpServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;
937 } else {
938 IScsiController = NetLibGetNicHandle (ControllerHandle, &gEfiTcp6ProtocolGuid);
939 ASSERT (IScsiController != NULL);
940 ProtocolGuid = &mIScsiV6PrivateGuid;
941 TcpProtocolGuid = &gEfiTcp6ProtocolGuid;
942 TcpServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;
943 }
944
945 Status = gBS->OpenProtocol (
946 IScsiController,
947 ProtocolGuid,
948 (VOID **) &IScsiIdentifier,
949 This->DriverBindingHandle,
950 ControllerHandle,
951 EFI_OPEN_PROTOCOL_GET_PROTOCOL
952 );
953 if (EFI_ERROR (Status)) {
954 return EFI_DEVICE_ERROR;
955 }
956
957 Private = ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier);
958 ASSERT (Private != NULL);
959
960 if (Private->ChildHandle != NULL) {
961 Status = gBS->CloseProtocol (
962 Private->ChildHandle,
963 TcpProtocolGuid,
964 This->DriverBindingHandle,
965 IScsiController
966 );
967
968 ASSERT (!EFI_ERROR (Status));
969
970 Status = NetLibDestroyServiceChild (
971 IScsiController,
972 This->DriverBindingHandle,
973 TcpServiceBindingGuid,
974 Private->ChildHandle
975 );
976
977 ASSERT (!EFI_ERROR (Status));
978 }
979
980 gBS->UninstallProtocolInterface (
981 IScsiController,
982 ProtocolGuid,
983 &Private->IScsiIdentifier
984 );
985
986 //
987 // Remove this NIC.
988 //
989 IScsiRemoveNic (IScsiController);
990
991 //
992 // Update the iSCSI Boot Firware Table.
993 //
994 IScsiPublishIbft ();
995
996 if (Private->Session != NULL) {
997 IScsiSessionAbort (Private->Session);
998 }
999
1000 IScsiCleanDriverData (Private);
1001
1002 return EFI_SUCCESS;
1003 }
1004
1005
1006 /**
1007 Unload the iSCSI driver.
1008
1009 @param[in] ImageHandle The handle of the driver image.
1010
1011 @retval EFI_SUCCESS The driver is unloaded.
1012 @retval EFI_DEVICE_ERROR An unexpected error occurred.
1013
1014 **/
1015 EFI_STATUS
1016 EFIAPI
1017 IScsiUnload (
1018 IN EFI_HANDLE ImageHandle
1019 )
1020 {
1021 EFI_STATUS Status;
1022 UINTN DeviceHandleCount;
1023 EFI_HANDLE *DeviceHandleBuffer;
1024 UINTN Index;
1025
1026 //
1027 // Try to disonnect the driver from the devices it's controlling.
1028 //
1029 Status = gBS->LocateHandleBuffer (
1030 AllHandles,
1031 NULL,
1032 NULL,
1033 &DeviceHandleCount,
1034 &DeviceHandleBuffer
1035 );
1036 if (!EFI_ERROR (Status)) {
1037 for (Index = 0; Index < DeviceHandleCount; Index++) {
1038 Status = gBS->DisconnectController (
1039 DeviceHandleBuffer[Index],
1040 ImageHandle,
1041 NULL
1042 );
1043 }
1044
1045 if (DeviceHandleBuffer != NULL) {
1046 FreePool (DeviceHandleBuffer);
1047 }
1048 }
1049 //
1050 // Unload the iSCSI configuration form.
1051 //
1052 IScsiConfigFormUnload (gIScsiDriverBinding.DriverBindingHandle);
1053
1054 //
1055 // Uninstall the protocols installed by iSCSI driver.
1056 //
1057 gBS->UninstallMultipleProtocolInterfaces (
1058 ImageHandle,
1059 &gEfiAuthenticationInfoProtocolGuid,
1060 &gIScsiAuthenticationInfo,
1061 NULL
1062 );
1063
1064 return gBS->UninstallMultipleProtocolInterfaces (
1065 ImageHandle,
1066 &gEfiDriverBindingProtocolGuid,
1067 &gIScsiDriverBinding,
1068 &gEfiComponentName2ProtocolGuid,
1069 &gIScsiComponentName2,
1070 &gEfiComponentNameProtocolGuid,
1071 &gIScsiComponentName,
1072 &gEfiIScsiInitiatorNameProtocolGuid,
1073 &gIScsiInitiatorName,
1074 NULL
1075 );
1076 }
1077
1078 /**
1079 This is the declaration of an EFI image entry point. This entry point is
1080 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
1081 both device drivers and bus drivers.
1082
1083 The entry point for iSCSI driver which initializes the global variables and
1084 installs the driver binding, component name protocol, iSCSI initiator name
1085 protocol and Authentication Info protocol on its image.
1086
1087 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
1088 @param[in] SystemTable A pointer to the EFI System Table.
1089
1090 @retval EFI_SUCCESS The operation completed successfully.
1091 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1092
1093 **/
1094 EFI_STATUS
1095 EFIAPI
1096 IScsiDriverEntryPoint (
1097 IN EFI_HANDLE ImageHandle,
1098 IN EFI_SYSTEM_TABLE *SystemTable
1099 )
1100 {
1101 EFI_STATUS Status;
1102 EFI_ISCSI_INITIATOR_NAME_PROTOCOL *IScsiInitiatorName;
1103 EFI_AUTHENTICATION_INFO_PROTOCOL *AuthenticationInfo;
1104
1105 //
1106 // There should be only one EFI_ISCSI_INITIATOR_NAME_PROTOCOL.
1107 //
1108 Status = gBS->LocateProtocol (
1109 &gEfiIScsiInitiatorNameProtocolGuid,
1110 NULL,
1111 (VOID **) &IScsiInitiatorName
1112 );
1113 if (!EFI_ERROR (Status)) {
1114 return EFI_ACCESS_DENIED;
1115 }
1116
1117 //
1118 // Initialize the EFI Driver Library.
1119 //
1120 Status = EfiLibInstallDriverBindingComponentName2 (
1121 ImageHandle,
1122 SystemTable,
1123 &gIScsiDriverBinding,
1124 ImageHandle,
1125 &gIScsiComponentName,
1126 &gIScsiComponentName2
1127 );
1128 if (EFI_ERROR (Status)) {
1129 return Status;
1130 }
1131
1132 //
1133 // Install the iSCSI Initiator Name Protocol.
1134 //
1135 Status = gBS->InstallProtocolInterface (
1136 &ImageHandle,
1137 &gEfiIScsiInitiatorNameProtocolGuid,
1138 EFI_NATIVE_INTERFACE,
1139 &gIScsiInitiatorName
1140 );
1141 if (EFI_ERROR (Status)) {
1142 goto Error1;
1143 }
1144
1145 //
1146 // Create the private data structures.
1147 //
1148 mPrivate = AllocateZeroPool (sizeof (ISCSI_PRIVATE_DATA));
1149 if (mPrivate == NULL) {
1150 Status = EFI_OUT_OF_RESOURCES;
1151 goto Error2;
1152 }
1153
1154 InitializeListHead (&mPrivate->NicInfoList);
1155 InitializeListHead (&mPrivate->AttemptConfigs);
1156
1157 //
1158 // Initialize the configuration form of iSCSI.
1159 //
1160 Status = IScsiConfigFormInit (gIScsiDriverBinding.DriverBindingHandle);
1161 if (EFI_ERROR (Status)) {
1162 goto Error3;
1163 }
1164
1165 //
1166 // There should be only one EFI_AUTHENTICATION_INFO_PROTOCOL. If already exists,
1167 // do not produce the protocol instance.
1168 //
1169 Status = gBS->LocateProtocol (
1170 &gEfiAuthenticationInfoProtocolGuid,
1171 NULL,
1172 (VOID **) &AuthenticationInfo
1173 );
1174 if (Status == EFI_NOT_FOUND) {
1175 Status = gBS->InstallProtocolInterface (
1176 &ImageHandle,
1177 &gEfiAuthenticationInfoProtocolGuid,
1178 EFI_NATIVE_INTERFACE,
1179 &gIScsiAuthenticationInfo
1180 );
1181 if (EFI_ERROR (Status)) {
1182 goto Error4;
1183 }
1184 }
1185
1186 return EFI_SUCCESS;
1187
1188 Error4:
1189 IScsiConfigFormUnload (gIScsiDriverBinding.DriverBindingHandle);
1190
1191 Error3:
1192 FreePool (mPrivate);
1193
1194 Error2:
1195 gBS->UninstallMultipleProtocolInterfaces (
1196 ImageHandle,
1197 &gEfiIScsiInitiatorNameProtocolGuid,
1198 &gIScsiInitiatorName,
1199 NULL
1200 );
1201
1202 Error1:
1203 gBS->UninstallMultipleProtocolInterfaces (
1204 ImageHandle,
1205 &gEfiDriverBindingProtocolGuid,
1206 &gIScsiDriverBinding,
1207 &gEfiComponentName2ProtocolGuid,
1208 &gIScsiComponentName2,
1209 &gEfiComponentNameProtocolGuid,
1210 &gIScsiComponentName,
1211 NULL
1212 );
1213
1214 return Status;
1215 }
1216