IScsiDriver.c revision 7a444476b4ffb405006ee36d0f2cec80c2d4b348
1/*++
2
3Copyright (c) 2004 - 2007, Intel Corporation
4All rights reserved. This program and the accompanying materials
5are licensed and made available under the terms and conditions of the BSD License
6which accompanies this distribution.  The full text of the license may be found at
7http://opensource.org/licenses/bsd-license.php
8
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12Module Name:
13
14  IScsiDriver.c
15
16Abstract:
17
18--*/
19
20#include "IScsiImpl.h"
21
22EFI_DRIVER_BINDING_PROTOCOL gIScsiDriverBinding = {
23  IScsiDriverBindingSupported,
24  IScsiDriverBindingStart,
25  IScsiDriverBindingStop,
26  0xa,
27  NULL,
28  NULL
29};
30
31EFI_GUID                    mIScsiPrivateGuid   = ISCSI_PRIVATE_GUID;
32
33EFI_STATUS
34EFIAPI
35IScsiDriverBindingSupported (
36  IN EFI_DRIVER_BINDING_PROTOCOL  * This,
37  IN EFI_HANDLE                   ControllerHandle,
38  IN EFI_DEVICE_PATH_PROTOCOL     * RemainingDevicePath OPTIONAL
39  )
40/*++
41
42Routine Description:
43
44  Test to see if iSCSI driver supports the given controller.
45
46Arguments:
47
48  This                - Protocol instance pointer.
49  ControllerHandle    - Handle of controller to test.
50  RemainingDevicePath - Optional parameter use to pick a specific child device to start.
51
52Returns:
53
54  EFI_SUCCES          - This driver supports the controller.
55  EFI_ALREADY_STARTED - This driver is already running on this device.
56  EFI_UNSUPPORTED     - This driver doesn't support the controller.
57
58--*/
59{
60  EFI_STATUS                Status;
61  EFI_DEVICE_PATH_PROTOCOL  *CurrentDevicePath;
62
63  Status = gBS->OpenProtocol (
64                  ControllerHandle,
65                  &mIScsiPrivateGuid,
66                  NULL,
67                  This->DriverBindingHandle,
68                  ControllerHandle,
69                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
70                  );
71  if (!EFI_ERROR (Status)) {
72    return EFI_ALREADY_STARTED;
73  }
74
75  Status = gBS->OpenProtocol (
76                  ControllerHandle,
77                  &gEfiTcp4ServiceBindingProtocolGuid,
78                  NULL,
79                  This->DriverBindingHandle,
80                  ControllerHandle,
81                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
82                  );
83  if (EFI_ERROR (Status)) {
84    return EFI_UNSUPPORTED;
85  }
86
87  CurrentDevicePath = RemainingDevicePath;
88  if (CurrentDevicePath != NULL) {
89    while (!IsDevicePathEnd (CurrentDevicePath)) {
90      if ((CurrentDevicePath->Type == MESSAGING_DEVICE_PATH) && (CurrentDevicePath->SubType == MSG_ISCSI_DP)) {
91        return EFI_SUCCESS;
92      }
93
94      CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
95    }
96
97    return EFI_UNSUPPORTED;
98  }
99
100  return EFI_SUCCESS;
101}
102
103EFI_STATUS
104EFIAPI
105IScsiDriverBindingStart (
106  IN EFI_DRIVER_BINDING_PROTOCOL  * This,
107  IN EFI_HANDLE                   ControllerHandle,
108  IN EFI_DEVICE_PATH_PROTOCOL     * RemainingDevicePath OPTIONAL
109  )
110/*++
111
112Routine Description:
113
114  Start to manage the controller.
115
116Arguments:
117
118  This                - Protocol instance pointer.
119  ControllerHandle    - Handle of the controller.
120  RemainingDevicePath - Optional parameter use to pick a specific child device to start.
121
122Returns:
123
124  EFI_SUCCES          - This driver supports this device.
125  EFI_ALREADY_STARTED - This driver is already running on this device.
126
127--*/
128{
129  EFI_STATUS        Status;
130  ISCSI_DRIVER_DATA *Private;
131
132  //
133  // Try to add a port configuration page for this controller.
134  //
135  IScsiConfigUpdateForm (This->DriverBindingHandle, ControllerHandle, TRUE);
136
137  Private = IScsiCreateDriverData (This->DriverBindingHandle, ControllerHandle);
138  if (Private == NULL) {
139    return EFI_OUT_OF_RESOURCES;
140  }
141  //
142  // Get the iSCSI configuration data of this controller.
143  //
144  Status = IScsiGetConfigData (Private);
145  if (EFI_ERROR (Status)) {
146    goto ON_ERROR;
147  }
148  //
149  // Try to login and create an iSCSI session according to the configuration.
150  //
151  Status = IScsiSessionLogin (Private);
152  if (Status == EFI_MEDIA_CHANGED) {
153    //
154    // The specified target is not available and the redirection information is
155    // got, login the session again with the updated target address.
156    //
157    Status = IScsiSessionLogin (Private);
158  }
159
160  if (EFI_ERROR (Status)) {
161    goto ON_ERROR;
162  }
163  //
164  // Duplicate the Session's tcp connection device path. The source port field
165  // will be set to zero as one iSCSI session is comprised of several iSCSI
166  // connections.
167  //
168  Private->DevicePath = IScsiGetTcpConnDevicePath (Private);
169  if (Private->DevicePath == NULL) {
170    goto ON_ERROR;
171  }
172  //
173  // Install the updated device path onto the ExtScsiPassThruHandle.
174  //
175  Status = gBS->InstallProtocolInterface (
176                  &Private->ExtScsiPassThruHandle,
177                  &gEfiDevicePathProtocolGuid,
178                  EFI_NATIVE_INTERFACE,
179                  Private->DevicePath
180                  );
181  if (EFI_ERROR (Status)) {
182    goto ON_ERROR;
183  }
184  //
185  // Install the iSCSI private stuff as a flag to indicate this controller
186  // is already controlled by iSCSI driver.
187  //
188  Status = gBS->InstallProtocolInterface (
189                  &ControllerHandle,
190                  &mIScsiPrivateGuid,
191                  EFI_NATIVE_INTERFACE,
192                  &Private->IScsiIdentifier
193                  );
194  if (EFI_ERROR (Status)) {
195    goto ON_ERROR;
196  }
197  //
198  // Update/Publish the iSCSI Boot Firmware Table.
199  //
200  IScsiPublishIbft ();
201
202  return EFI_SUCCESS;
203
204ON_ERROR:
205
206  IScsiSessionAbort (&Private->Session);
207  IScsiCleanDriverData (Private);
208
209  return Status;
210}
211
212EFI_STATUS
213EFIAPI
214IScsiDriverBindingStop (
215  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
216  IN EFI_HANDLE                   ControllerHandle,
217  IN UINTN                        NumberOfChildren,
218  IN EFI_HANDLE                   *ChildHandleBuffer
219  )
220/*++
221
222Routine Description:
223
224  Release the control of this controller and remove the iSCSI functions.
225
226Arguments:
227
228  This                - Protocol instance pointer.
229  ControllerHandle    - Handle of controller to stop.
230  NumberOfChildren    - Not used.
231  ChildHandleBuffer   - Not used.
232
233Returns:
234
235  EFI_SUCCES          - This driver supports this device.
236
237--*/
238{
239  EFI_HANDLE                      IScsiController;
240  EFI_STATUS                      Status;
241  ISCSI_PRIVATE_PROTOCOL          *IScsiIdentifier;
242  ISCSI_DRIVER_DATA               *Private;
243  EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
244  ISCSI_CONNECTION                *Conn;
245
246  if (NumberOfChildren != 0) {
247    //
248    // We should have only one child.
249    //
250    Status = gBS->OpenProtocol (
251                    ChildHandleBuffer[0],
252                    &gEfiExtScsiPassThruProtocolGuid,
253                    (VOID **) &PassThru,
254                    This->DriverBindingHandle,
255                    ControllerHandle,
256                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
257                    );
258    if (EFI_ERROR (Status)) {
259      return EFI_DEVICE_ERROR;
260    }
261
262    Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (PassThru);
263    Conn    = NET_LIST_HEAD (&Private->Session.Conns, ISCSI_CONNECTION, Link);
264
265    //
266    // Previously the TCP4 protocol is opened BY_CHILD_CONTROLLER. Just close
267    // the protocol here but not uninstall the device path protocol and
268    // EXT SCSI PASS THRU protocol installed on ExtScsiPassThruHandle.
269    //
270    gBS->CloseProtocol (
271          Conn->Tcp4Io.Handle,
272          &gEfiTcp4ProtocolGuid,
273          Private->Image,
274          Private->ExtScsiPassThruHandle
275          );
276
277    return EFI_SUCCESS;
278  }
279  //
280  // Get the handle of the controller we are controling.
281  //
282  IScsiController = NetLibGetNicHandle (ControllerHandle, &gEfiTcp4ProtocolGuid);
283
284  Status = gBS->OpenProtocol (
285                  IScsiController,
286                  &mIScsiPrivateGuid,
287                  (VOID **)&IScsiIdentifier,
288                  This->DriverBindingHandle,
289                  ControllerHandle,
290                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
291                  );
292  if (EFI_ERROR (Status)) {
293    return EFI_DEVICE_ERROR;
294  }
295
296  Private = ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier);
297
298  //
299  // Uninstall the private protocol.
300  //
301  gBS->UninstallProtocolInterface (
302        IScsiController,
303        &mIScsiPrivateGuid,
304        &Private->IScsiIdentifier
305        );
306
307  //
308  // Update the iSCSI Boot Firware Table.
309  //
310  IScsiPublishIbft ();
311
312  IScsiSessionAbort (&Private->Session);
313  IScsiCleanDriverData (Private);
314
315  return EFI_SUCCESS;
316}
317
318EFI_STATUS
319EFIAPI
320EfiIScsiUnload (
321  IN EFI_HANDLE  ImageHandle
322  )
323/*++
324
325Routine Description:
326
327  Unload the iSCSI driver.
328
329Arguments:
330
331  ImageHandle - The handle of the driver image.
332
333Returns:
334
335  EFI_SUCCESS      - The driver is unloaded.
336  EFI_DEVICE_ERROR - Some unexpected error happened.
337
338--*/
339{
340  EFI_STATUS  Status;
341  UINTN       DeviceHandleCount;
342  EFI_HANDLE  *DeviceHandleBuffer;
343  UINTN       Index;
344
345  //
346  // Try to disonnect the driver from the devices it's controlling.
347  //
348  Status = gBS->LocateHandleBuffer (
349                  AllHandles,
350                  NULL,
351                  NULL,
352                  &DeviceHandleCount,
353                  &DeviceHandleBuffer
354                  );
355  if (!EFI_ERROR (Status)) {
356    for (Index = 0; Index < DeviceHandleCount; Index++) {
357      Status = gBS->DisconnectController (
358                      DeviceHandleBuffer[Index],
359                      ImageHandle,
360                      NULL
361                      );
362    }
363
364    if (DeviceHandleBuffer != NULL) {
365      NetFreePool (DeviceHandleBuffer);
366    }
367  }
368  //
369  // Unload the iSCSI configuration form.
370  //
371  IScsiConfigFormUnload (gIScsiDriverBinding.DriverBindingHandle);
372
373  //
374  // Uninstall the protocols installed by iSCSI driver.
375  //
376  Status = gBS->UninstallMultipleProtocolInterfaces (
377                  ImageHandle,
378                  &gEfiDriverBindingProtocolGuid,
379                  &gIScsiDriverBinding,
380                  &gEfiComponentName2ProtocolGuid,
381                  &gIScsiComponentName2,
382                  &gEfiComponentNameProtocolGuid,
383                  &gIScsiComponentName,
384                  &gEfiIScsiInitiatorNameProtocolGuid,
385                  &gIScsiInitiatorName,
386                  NULL
387                  );
388
389  return Status;
390}
391
392EFI_STATUS
393EFIAPI
394IScsiDriverEntryPoint (
395  IN EFI_HANDLE         ImageHandle,
396  IN EFI_SYSTEM_TABLE   *SystemTable
397  )
398/*++
399
400Routine Description:
401
402  Initialize the global variables publish the driver binding protocol.
403
404Arguments:
405
406  ImageHandle - The handle of the driver image.
407  SystemTable - The EFI system table.
408
409Returns:
410
411  EFI_SUCCESS      - The protocols are installed.
412  EFI_DEVICE_ERROR - Some unexpected error happened.
413
414--*/
415{
416  EFI_STATUS  Status;
417  //EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
418
419  //
420  // Initialize the EFI Driver Library
421  //
422  Status = EfiLibInstallDriverBindingComponentName2 (
423             ImageHandle,
424             SystemTable,
425             &gIScsiDriverBinding,
426             ImageHandle,
427             &gIScsiComponentName,
428             &gIScsiComponentName2
429           );
430
431  if (EFI_ERROR (Status)) {
432    return Status;
433  }
434
435  if (!EFI_ERROR (Status)) {
436    Status = gBS->InstallProtocolInterface (
437                    &ImageHandle,
438                    &gEfiIScsiInitiatorNameProtocolGuid,
439                    EFI_NATIVE_INTERFACE,
440                    &gIScsiInitiatorName
441                    );
442    if (EFI_ERROR (Status)) {
443      gBS->UninstallMultipleProtocolInterfaces (
444            ImageHandle,
445            &gEfiDriverBindingProtocolGuid,
446            &gIScsiDriverBinding,
447            &gEfiComponentName2ProtocolGuid,
448            &gIScsiComponentName2,
449            &gEfiComponentNameProtocolGuid,
450            &gIScsiComponentName,
451            NULL
452            );
453    }
454  }
455  //
456  // Initialize the configuration form of iSCSI.
457  //
458  IScsiConfigFormInit (gIScsiDriverBinding.DriverBindingHandle);
459
460  return Status;
461}
462
463