• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   SCSI Bus driver that layers on every SCSI Pass Thru and
3   Extended SCSI Pass Thru protocol in the system.
4 
5 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution.  The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10 
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 
17 #include "ScsiBus.h"
18 
19 
20 EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding = {
21   SCSIBusDriverBindingSupported,
22   SCSIBusDriverBindingStart,
23   SCSIBusDriverBindingStop,
24   0xa,
25   NULL,
26   NULL
27 };
28 
29 VOID  *mWorkingBuffer;
30 
31 /**
32   Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.
33 
34   @param  Packet         The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
35   @param  CommandPacket  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
36 
37 **/
38 EFI_STATUS
39 EFIAPI
40 ScsiioToPassThruPacket (
41   IN      EFI_SCSI_IO_SCSI_REQUEST_PACKET         *Packet,
42   OUT     EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *CommandPacket
43   );
44 
45 /**
46   Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.
47 
48   @param  ScsiPacket  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
49   @param  Packet      The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
50 
51 **/
52 EFI_STATUS
53 EFIAPI
54 PassThruToScsiioPacket (
55   IN     EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *ScsiPacket,
56   OUT    EFI_SCSI_IO_SCSI_REQUEST_PACKET         *Packet
57   );
58 
59 /**
60   Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
61   SCSI IO Packet.
62 
63   @param  Event    The instance of EFI_EVENT.
64   @param  Context  The parameter passed in.
65 
66 **/
67 VOID
68 EFIAPI
69 NotifyFunction (
70   IN  EFI_EVENT  Event,
71   IN  VOID       *Context
72   );
73 
74 /**
75   Allocates an aligned buffer for SCSI device.
76 
77   This function allocates an aligned buffer for the SCSI device to perform
78   SCSI pass through operations. The alignment requirement is from SCSI pass
79   through interface.
80 
81   @param  ScsiIoDevice      The SCSI child device involved for the operation.
82   @param  BufferSize        The request buffer size.
83 
84   @return A pointer to the aligned buffer or NULL if the allocation fails.
85 
86 **/
87 VOID *
AllocateAlignedBuffer(IN SCSI_IO_DEV * ScsiIoDevice,IN UINTN BufferSize)88 AllocateAlignedBuffer (
89   IN SCSI_IO_DEV              *ScsiIoDevice,
90   IN UINTN                    BufferSize
91   )
92 {
93   return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), ScsiIoDevice->ScsiIo.IoAlign);
94 }
95 
96 /**
97   Frees an aligned buffer for SCSI device.
98 
99   This function frees an aligned buffer for the SCSI device to perform
100   SCSI pass through operations.
101 
102   @param  Buffer            The aligned buffer to be freed.
103   @param  BufferSize        The request buffer size.
104 
105 **/
106 VOID
FreeAlignedBuffer(IN VOID * Buffer,IN UINTN BufferSize)107 FreeAlignedBuffer (
108   IN VOID                     *Buffer,
109   IN UINTN                    BufferSize
110   )
111 {
112   if (Buffer != NULL) {
113     FreeAlignedPages (Buffer, EFI_SIZE_TO_PAGES (BufferSize));
114   }
115 }
116 
117 /**
118   The user Entry Point for module ScsiBus. The user code starts with this function.
119 
120   @param  ImageHandle    The firmware allocated handle for the EFI image.
121   @param  SystemTable    A pointer to the EFI System Table.
122 
123   @retval EFI_SUCCESS    The entry point is executed successfully.
124   @retval other          Some error occurs when executing this entry point.
125 
126 **/
127 EFI_STATUS
128 EFIAPI
InitializeScsiBus(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)129 InitializeScsiBus(
130   IN EFI_HANDLE           ImageHandle,
131   IN EFI_SYSTEM_TABLE     *SystemTable
132   )
133 {
134   EFI_STATUS              Status;
135 
136   //
137   // Install driver model protocol(s).
138   //
139   Status = EfiLibInstallDriverBindingComponentName2 (
140              ImageHandle,
141              SystemTable,
142              &gSCSIBusDriverBinding,
143              ImageHandle,
144              &gScsiBusComponentName,
145              &gScsiBusComponentName2
146              );
147   ASSERT_EFI_ERROR (Status);
148 
149   return Status;
150 }
151 
152 
153 /**
154   Test to see if this driver supports ControllerHandle.
155 
156   This service is called by the EFI boot service ConnectController(). In order
157   to make drivers as small as possible, there are a few calling restrictions for
158   this service. ConnectController() must follow these calling restrictions. If
159   any other agent wishes to call Supported() it must also follow these calling
160   restrictions.
161 
162   @param  This                Protocol instance pointer.
163   @param  ControllerHandle    Handle of device to test
164   @param  RemainingDevicePath Optional parameter use to pick a specific child
165                               device to start.
166 
167   @retval EFI_SUCCESS         This driver supports this device
168   @retval EFI_ALREADY_STARTED This driver is already running on this device
169   @retval other               This driver does not support this device
170 
171 **/
172 EFI_STATUS
173 EFIAPI
SCSIBusDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)174 SCSIBusDriverBindingSupported (
175   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
176   IN EFI_HANDLE                   Controller,
177   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
178   )
179 {
180   EFI_STATUS                      Status;
181   EFI_SCSI_PASS_THRU_PROTOCOL     *PassThru;
182   EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtPassThru;
183   UINT64                          Lun;
184   UINT8                           *TargetId;
185   SCSI_TARGET_ID                  ScsiTargetId;
186 
187   TargetId = &ScsiTargetId.ScsiId.ExtScsi[0];
188   SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);
189 
190   //
191   // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
192   // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
193   // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
194   //
195   Status = gBS->OpenProtocol (
196                   Controller,
197                   &gEfiExtScsiPassThruProtocolGuid,
198                   (VOID **)&ExtPassThru,
199                   This->DriverBindingHandle,
200                   Controller,
201                   EFI_OPEN_PROTOCOL_BY_DRIVER
202                   );
203 
204   if (Status == EFI_ALREADY_STARTED) {
205     return EFI_SUCCESS;
206   } else if (!EFI_ERROR(Status)) {
207     //
208     // Check if RemainingDevicePath is NULL or the End of Device Path Node,
209     // if yes, return EFI_SUCCESS.
210     //
211     if ((RemainingDevicePath == NULL) || IsDevicePathEnd (RemainingDevicePath)) {
212       //
213       // Close protocol regardless of RemainingDevicePath validation
214       //
215       gBS->CloseProtocol (
216              Controller,
217              &gEfiExtScsiPassThruProtocolGuid,
218              This->DriverBindingHandle,
219              Controller
220              );
221       return EFI_SUCCESS;
222     } else {
223       //
224       // If RemainingDevicePath isn't the End of Device Path Node, check its validation
225       //
226       Status = ExtPassThru->GetTargetLun (ExtPassThru, RemainingDevicePath, &TargetId, &Lun);
227       //
228       // Close protocol regardless of RemainingDevicePath validation
229       //
230       gBS->CloseProtocol (
231              Controller,
232              &gEfiExtScsiPassThruProtocolGuid,
233              This->DriverBindingHandle,
234              Controller
235              );
236       if (!EFI_ERROR(Status)) {
237         return EFI_SUCCESS;
238       }
239     }
240   }
241 
242   //
243   // Come here in 2 condition:
244   // 1. ExtPassThru doesn't exist.
245   // 2. ExtPassThru exists but RemainingDevicePath is invalid.
246   //
247   Status = gBS->OpenProtocol (
248                   Controller,
249                   &gEfiScsiPassThruProtocolGuid,
250                   (VOID **)&PassThru,
251                   This->DriverBindingHandle,
252                   Controller,
253                   EFI_OPEN_PROTOCOL_BY_DRIVER
254                   );
255 
256   if (Status == EFI_ALREADY_STARTED) {
257     return EFI_SUCCESS;
258   }
259 
260   if (EFI_ERROR (Status)) {
261     return Status;
262   }
263 
264   //
265   // Test RemainingDevicePath is valid or not.
266   //
267   if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {
268     Status = PassThru->GetTargetLun (PassThru, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun);
269   }
270 
271   gBS->CloseProtocol (
272          Controller,
273          &gEfiScsiPassThruProtocolGuid,
274          This->DriverBindingHandle,
275          Controller
276          );
277   return Status;
278 }
279 
280 
281 /**
282   Start this driver on ControllerHandle.
283 
284   This service is called by the EFI boot service ConnectController(). In order
285   to make drivers as small as possible, there are a few calling restrictions for
286   this service. ConnectController() must follow these calling restrictions. If
287   any other agent wishes to call Start() it must also follow these calling
288   restrictions.
289 
290   @param  This                 Protocol instance pointer.
291   @param  ControllerHandle     Handle of device to bind driver to
292   @param  RemainingDevicePath  Optional parameter use to pick a specific child
293                                device to start.
294 
295   @retval EFI_SUCCESS          This driver is added to ControllerHandle
296   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
297   @retval other                This driver does not support this device
298 
299 **/
300 EFI_STATUS
301 EFIAPI
SCSIBusDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)302 SCSIBusDriverBindingStart (
303   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
304   IN EFI_HANDLE                   Controller,
305   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
306   )
307 {
308   UINT64                                Lun;
309   UINT8                                 *TargetId;
310   BOOLEAN                               ScanOtherPuns;
311   BOOLEAN                               FromFirstTarget;
312   BOOLEAN                               ExtScsiSupport;
313   EFI_STATUS                            Status;
314   EFI_STATUS                            DevicePathStatus;
315   EFI_STATUS                            PassThruStatus;
316   SCSI_BUS_DEVICE                       *ScsiBusDev;
317   SCSI_TARGET_ID                        ScsiTargetId;
318   EFI_DEVICE_PATH_PROTOCOL              *ParentDevicePath;
319   EFI_SCSI_PASS_THRU_PROTOCOL           *ScsiInterface;
320   EFI_EXT_SCSI_PASS_THRU_PROTOCOL       *ExtScsiInterface;
321   EFI_SCSI_BUS_PROTOCOL                 *BusIdentify;
322 
323   TargetId        = NULL;
324   ScanOtherPuns   = TRUE;
325   FromFirstTarget = FALSE;
326   ExtScsiSupport  = FALSE;
327   PassThruStatus  = EFI_SUCCESS;
328 
329   TargetId = &ScsiTargetId.ScsiId.ExtScsi[0];
330   SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);
331 
332   DevicePathStatus = gBS->OpenProtocol (
333                             Controller,
334                             &gEfiDevicePathProtocolGuid,
335                             (VOID **) &ParentDevicePath,
336                             This->DriverBindingHandle,
337                             Controller,
338                             EFI_OPEN_PROTOCOL_BY_DRIVER
339                             );
340   if (EFI_ERROR (DevicePathStatus) && (DevicePathStatus != EFI_ALREADY_STARTED)) {
341     return DevicePathStatus;
342   }
343 
344   //
345   // Report Status Code to indicate SCSI bus starts
346   //
347   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
348     EFI_PROGRESS_CODE,
349     (EFI_IO_BUS_SCSI | EFI_IOB_PC_INIT),
350     ParentDevicePath
351     );
352 
353   //
354   // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
355   // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
356   // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
357   //
358   Status = gBS->OpenProtocol (
359                   Controller,
360                   &gEfiExtScsiPassThruProtocolGuid,
361                   (VOID **) &ExtScsiInterface,
362                   This->DriverBindingHandle,
363                   Controller,
364                   EFI_OPEN_PROTOCOL_BY_DRIVER
365                   );
366   //
367   // Fail to open UEFI ExtendPassThru Protocol, then try to open EFI PassThru Protocol instead.
368   //
369   if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) {
370     Status = gBS->OpenProtocol (
371                     Controller,
372                     &gEfiScsiPassThruProtocolGuid,
373                     (VOID **) &ScsiInterface,
374                     This->DriverBindingHandle,
375                     Controller,
376                     EFI_OPEN_PROTOCOL_BY_DRIVER
377                     );
378     //
379     // Fail to open EFI PassThru Protocol, Close the DevicePathProtocol if it is opened by this time.
380     //
381     if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
382       if (!EFI_ERROR(DevicePathStatus)) {
383         gBS->CloseProtocol (
384                Controller,
385                &gEfiDevicePathProtocolGuid,
386                This->DriverBindingHandle,
387                Controller
388                );
389       }
390       return Status;
391     }
392   } else {
393     //
394     // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol
395     // with BY_DRIVER if it is also present on the handle. The intent is to prevent
396     // another SCSI Bus Driver to work on the same host handle.
397     //
398     ExtScsiSupport = TRUE;
399     PassThruStatus = gBS->OpenProtocol (
400                             Controller,
401                             &gEfiScsiPassThruProtocolGuid,
402                             (VOID **) &ScsiInterface,
403                             This->DriverBindingHandle,
404                             Controller,
405                             EFI_OPEN_PROTOCOL_BY_DRIVER
406                             );
407   }
408 
409   if (Status != EFI_ALREADY_STARTED) {
410     //
411     // Go through here means either ExtPassThru or PassThru Protocol is successfully opened
412     // on this handle for this time. Then construct Host controller private data.
413     //
414     ScsiBusDev = NULL;
415     ScsiBusDev = AllocateZeroPool(sizeof(SCSI_BUS_DEVICE));
416     if (ScsiBusDev == NULL) {
417       Status = EFI_OUT_OF_RESOURCES;
418       goto ErrorExit;
419     }
420     ScsiBusDev->Signature        = SCSI_BUS_DEVICE_SIGNATURE;
421     ScsiBusDev->ExtScsiSupport   = ExtScsiSupport;
422     ScsiBusDev->DevicePath       = ParentDevicePath;
423     if (ScsiBusDev->ExtScsiSupport) {
424       ScsiBusDev->ExtScsiInterface = ExtScsiInterface;
425     } else {
426       ScsiBusDev->ScsiInterface    = ScsiInterface;
427     }
428 
429     //
430     // Install EFI_SCSI_BUS_PROTOCOL to the controller handle, So ScsiBusDev could be
431     // retrieved on this controller handle. With ScsiBusDev, we can know which PassThru
432     // Protocol is present on the handle, UEFI ExtPassThru Protocol or EFI PassThru Protocol.
433     //
434     Status = gBS->InstallProtocolInterface (
435                     &Controller,
436                     &gEfiCallerIdGuid,
437                     EFI_NATIVE_INTERFACE,
438                     &ScsiBusDev->BusIdentify
439                     );
440     if (EFI_ERROR (Status)) {
441       goto ErrorExit;
442     }
443   } else {
444     //
445     // Go through here means Start() is re-invoked again, nothing special is required to do except
446     // picking up Host controller private information.
447     //
448     Status = gBS->OpenProtocol (
449                     Controller,
450                     &gEfiCallerIdGuid,
451                     (VOID **) &BusIdentify,
452                     This->DriverBindingHandle,
453                     Controller,
454                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
455                     );
456 
457     if (EFI_ERROR (Status)) {
458       return Status;
459     }
460     ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify);
461   }
462 
463   //
464   // Report Status Code to indicate detecting devices on bus
465   //
466   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
467     EFI_PROGRESS_CODE,
468     (EFI_IO_BUS_SCSI | EFI_IOB_PC_DETECT),
469     ParentDevicePath
470     );
471 
472   Lun  = 0;
473   if (RemainingDevicePath == NULL) {
474     //
475     // If RemainingDevicePath is NULL,
476     // must enumerate all SCSI devices anyway
477     //
478     FromFirstTarget = TRUE;
479   } else if (!IsDevicePathEnd (RemainingDevicePath)) {
480     //
481     // If RemainingDevicePath isn't the End of Device Path Node,
482     // only scan the specified device by RemainingDevicePath
483     //
484     if (ScsiBusDev->ExtScsiSupport) {
485       Status = ScsiBusDev->ExtScsiInterface->GetTargetLun (ScsiBusDev->ExtScsiInterface, RemainingDevicePath, &TargetId, &Lun);
486     } else {
487       Status = ScsiBusDev->ScsiInterface->GetTargetLun (ScsiBusDev->ScsiInterface, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun);
488     }
489 
490     if (EFI_ERROR (Status)) {
491       return Status;
492     }
493   } else {
494     //
495     // If RemainingDevicePath is the End of Device Path Node,
496     // skip enumerate any device and return EFI_SUCESSS
497     //
498     ScanOtherPuns = FALSE;
499   }
500 
501   while(ScanOtherPuns) {
502     if (FromFirstTarget) {
503       //
504       // Remaining Device Path is NULL, scan all the possible Puns in the
505       // SCSI Channel.
506       //
507       if (ScsiBusDev->ExtScsiSupport) {
508         Status = ScsiBusDev->ExtScsiInterface->GetNextTargetLun (ScsiBusDev->ExtScsiInterface, &TargetId, &Lun);
509       } else {
510         Status = ScsiBusDev->ScsiInterface->GetNextDevice (ScsiBusDev->ScsiInterface, &ScsiTargetId.ScsiId.Scsi, &Lun);
511       }
512       if (EFI_ERROR (Status)) {
513         //
514         // no legal Pun and Lun found any more
515         //
516         break;
517       }
518     } else {
519       ScanOtherPuns = FALSE;
520     }
521     //
522     // Avoid creating handle for the host adapter.
523     //
524     if (ScsiBusDev->ExtScsiSupport) {
525       if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ExtScsiInterface->Mode->AdapterId) {
526         continue;
527       }
528     } else {
529       if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ScsiInterface->Mode->AdapterId) {
530         continue;
531       }
532     }
533     //
534     // Scan for the scsi device, if it attaches to the scsi bus,
535     // then create handle and install scsi i/o protocol.
536     //
537     Status = ScsiScanCreateDevice (This, Controller, &ScsiTargetId, Lun, ScsiBusDev);
538   }
539   return EFI_SUCCESS;
540 
541 ErrorExit:
542 
543   if (ScsiBusDev != NULL) {
544     FreePool (ScsiBusDev);
545   }
546 
547   if (ExtScsiSupport) {
548     gBS->CloseProtocol (
549            Controller,
550            &gEfiExtScsiPassThruProtocolGuid,
551            This->DriverBindingHandle,
552            Controller
553            );
554     if (!EFI_ERROR (PassThruStatus)) {
555       gBS->CloseProtocol (
556              Controller,
557              &gEfiScsiPassThruProtocolGuid,
558              This->DriverBindingHandle,
559              Controller
560              );
561     }
562   } else {
563     gBS->CloseProtocol (
564            Controller,
565            &gEfiScsiPassThruProtocolGuid,
566            This->DriverBindingHandle,
567            Controller
568            );
569   }
570   return Status;
571 }
572 
573 /**
574   Stop this driver on ControllerHandle.
575 
576   This service is called by the EFI boot service DisconnectController().
577   In order to make drivers as small as possible, there are a few calling
578   restrictions for this service. DisconnectController() must follow these
579   calling restrictions. If any other agent wishes to call Stop() it must also
580   follow these calling restrictions.
581 
582   @param  This              Protocol instance pointer.
583   @param  ControllerHandle  Handle of device to stop driver on
584   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
585                             children is zero stop the entire bus driver.
586   @param  ChildHandleBuffer List of Child Handles to Stop.
587 
588   @retval EFI_SUCCESS       This driver is removed ControllerHandle
589   @retval other             This driver was not removed from this device
590 
591 **/
592 EFI_STATUS
593 EFIAPI
SCSIBusDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)594 SCSIBusDriverBindingStop (
595   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
596   IN  EFI_HANDLE                      Controller,
597   IN  UINTN                           NumberOfChildren,
598   IN  EFI_HANDLE                      *ChildHandleBuffer
599   )
600 {
601   EFI_STATUS                  Status;
602   BOOLEAN                     AllChildrenStopped;
603   UINTN                       Index;
604   EFI_SCSI_IO_PROTOCOL        *ScsiIo;
605   SCSI_IO_DEV                 *ScsiIoDevice;
606   VOID                        *ScsiPassThru;
607   EFI_SCSI_BUS_PROTOCOL       *Scsidentifier;
608   SCSI_BUS_DEVICE             *ScsiBusDev;
609 
610   if (NumberOfChildren == 0) {
611     //
612     // Get the SCSI_BUS_DEVICE
613     //
614     Status = gBS->OpenProtocol (
615                     Controller,
616                     &gEfiCallerIdGuid,
617                     (VOID **) &Scsidentifier,
618                     This->DriverBindingHandle,
619                     Controller,
620                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
621                     );
622 
623     if (EFI_ERROR (Status)) {
624       return EFI_DEVICE_ERROR;
625     }
626 
627     ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier);
628 
629     //
630     // Uninstall SCSI Bus Protocol
631     //
632     gBS->UninstallProtocolInterface (
633            Controller,
634            &gEfiCallerIdGuid,
635            &ScsiBusDev->BusIdentify
636            );
637 
638     //
639     // Close the bus driver
640     //
641     if (ScsiBusDev->ExtScsiSupport) {
642       //
643       // Close ExtPassThru Protocol from this controller handle
644       //
645       gBS->CloseProtocol (
646              Controller,
647              &gEfiExtScsiPassThruProtocolGuid,
648              This->DriverBindingHandle,
649              Controller
650              );
651       //
652       // When Start() succeeds to open ExtPassThru, it always tries to open PassThru BY_DRIVER.
653       // Its intent is to prevent another SCSI Bus Driver from woking on the same host handle.
654       // So Stop() needs to try to close PassThru if present here.
655       //
656       gBS->CloseProtocol (
657              Controller,
658              &gEfiScsiPassThruProtocolGuid,
659              This->DriverBindingHandle,
660              Controller
661              );
662     } else {
663       gBS->CloseProtocol (
664              Controller,
665              &gEfiScsiPassThruProtocolGuid,
666              This->DriverBindingHandle,
667              Controller
668              );
669     }
670 
671     gBS->CloseProtocol (
672            Controller,
673            &gEfiDevicePathProtocolGuid,
674            This->DriverBindingHandle,
675            Controller
676            );
677     FreePool (ScsiBusDev);
678     return EFI_SUCCESS;
679   }
680 
681   AllChildrenStopped = TRUE;
682 
683   for (Index = 0; Index < NumberOfChildren; Index++) {
684 
685     Status = gBS->OpenProtocol (
686                     ChildHandleBuffer[Index],
687                     &gEfiScsiIoProtocolGuid,
688                     (VOID **) &ScsiIo,
689                     This->DriverBindingHandle,
690                     Controller,
691                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
692                     );
693     if (EFI_ERROR (Status)) {
694       AllChildrenStopped = FALSE;
695       continue;
696     }
697 
698     ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (ScsiIo);
699     //
700     // Close the child handle
701     //
702     if (ScsiIoDevice->ExtScsiSupport) {
703       Status = gBS->CloseProtocol (
704                       Controller,
705                       &gEfiExtScsiPassThruProtocolGuid,
706                       This->DriverBindingHandle,
707                       ChildHandleBuffer[Index]
708                       );
709 
710     } else {
711       Status = gBS->CloseProtocol (
712                       Controller,
713                       &gEfiScsiPassThruProtocolGuid,
714                       This->DriverBindingHandle,
715                       ChildHandleBuffer[Index]
716                       );
717     }
718 
719     Status = gBS->UninstallMultipleProtocolInterfaces (
720                     ChildHandleBuffer[Index],
721                     &gEfiDevicePathProtocolGuid,
722                     ScsiIoDevice->DevicePath,
723                     &gEfiScsiIoProtocolGuid,
724                     &ScsiIoDevice->ScsiIo,
725                     NULL
726                     );
727     if (EFI_ERROR (Status)) {
728       AllChildrenStopped = FALSE;
729       if (ScsiIoDevice->ExtScsiSupport) {
730         gBS->OpenProtocol (
731                Controller,
732                &gEfiExtScsiPassThruProtocolGuid,
733                &ScsiPassThru,
734                This->DriverBindingHandle,
735                ChildHandleBuffer[Index],
736                EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
737                );
738       } else {
739         gBS->OpenProtocol (
740                Controller,
741                &gEfiScsiPassThruProtocolGuid,
742                &ScsiPassThru,
743                This->DriverBindingHandle,
744                ChildHandleBuffer[Index],
745                EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
746                );
747       }
748     } else {
749       FreePool (ScsiIoDevice);
750     }
751   }
752 
753   if (!AllChildrenStopped) {
754     return EFI_DEVICE_ERROR;
755   }
756 
757   return EFI_SUCCESS;
758 }
759 
760 
761 /**
762   Retrieves the device type information of the SCSI Controller.
763 
764   @param  This          Protocol instance pointer.
765   @param  DeviceType    A pointer to the device type information retrieved from
766                         the SCSI Controller.
767 
768   @retval EFI_SUCCESS             Retrieves the device type information successfully.
769   @retval EFI_INVALID_PARAMETER   The DeviceType is NULL.
770 
771 **/
772 EFI_STATUS
773 EFIAPI
ScsiGetDeviceType(IN EFI_SCSI_IO_PROTOCOL * This,OUT UINT8 * DeviceType)774 ScsiGetDeviceType (
775   IN  EFI_SCSI_IO_PROTOCOL     *This,
776   OUT UINT8                    *DeviceType
777   )
778 {
779   SCSI_IO_DEV *ScsiIoDevice;
780 
781   if (DeviceType == NULL) {
782     return EFI_INVALID_PARAMETER;
783   }
784 
785   ScsiIoDevice  = SCSI_IO_DEV_FROM_THIS (This);
786   *DeviceType   = ScsiIoDevice->ScsiDeviceType;
787   return EFI_SUCCESS;
788 }
789 
790 
791 /**
792   Retrieves the device location in the SCSI channel.
793 
794   @param  This   Protocol instance pointer.
795   @param  Target A pointer to the Target ID of a SCSI device
796                  on the SCSI channel.
797   @param  Lun    A pointer to the LUN of the SCSI device on
798                  the SCSI channel.
799 
800   @retval EFI_SUCCESS           Retrieves the device location successfully.
801   @retval EFI_INVALID_PARAMETER The Target or Lun is NULL.
802 
803 **/
804 EFI_STATUS
805 EFIAPI
ScsiGetDeviceLocation(IN EFI_SCSI_IO_PROTOCOL * This,IN OUT UINT8 ** Target,OUT UINT64 * Lun)806 ScsiGetDeviceLocation (
807   IN  EFI_SCSI_IO_PROTOCOL    *This,
808   IN OUT UINT8                **Target,
809   OUT UINT64                  *Lun
810   )
811 {
812   SCSI_IO_DEV *ScsiIoDevice;
813 
814   if (Target == NULL || Lun == NULL) {
815     return EFI_INVALID_PARAMETER;
816   }
817 
818   ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
819 
820   CopyMem (*Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);
821 
822   *Lun         = ScsiIoDevice->Lun;
823 
824   return EFI_SUCCESS;
825 }
826 
827 /**
828   Resets the SCSI Bus that the SCSI Controller is attached to.
829 
830   @param  This  Protocol instance pointer.
831 
832   @retval  EFI_SUCCESS       The SCSI bus is reset successfully.
833   @retval  EFI_DEVICE_ERROR  Errors encountered when resetting the SCSI bus.
834   @retval  EFI_UNSUPPORTED   The bus reset operation is not supported by the
835                              SCSI Host Controller.
836   @retval  EFI_TIMEOUT       A timeout occurred while attempting to reset
837                              the SCSI bus.
838 **/
839 EFI_STATUS
840 EFIAPI
ScsiResetBus(IN EFI_SCSI_IO_PROTOCOL * This)841 ScsiResetBus (
842   IN  EFI_SCSI_IO_PROTOCOL     *This
843   )
844 {
845   SCSI_IO_DEV *ScsiIoDevice;
846 
847   ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
848 
849   //
850   // Report Status Code to indicate reset happens
851   //
852   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
853     EFI_PROGRESS_CODE,
854     (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET),
855     ScsiIoDevice->ScsiBusDeviceData->DevicePath
856     );
857 
858   if (ScsiIoDevice->ExtScsiSupport){
859     return ScsiIoDevice->ExtScsiPassThru->ResetChannel (ScsiIoDevice->ExtScsiPassThru);
860   } else {
861     return ScsiIoDevice->ScsiPassThru->ResetChannel (ScsiIoDevice->ScsiPassThru);
862   }
863 }
864 
865 
866 /**
867   Resets the SCSI Controller that the device handle specifies.
868 
869   @param  This  Protocol instance pointer.
870 
871   @retval  EFI_SUCCESS       Reset the SCSI controller successfully.
872   @retval  EFI_DEVICE_ERROR  Errors are encountered when resetting the SCSI Controller.
873   @retval  EFI_UNSUPPORTED   The SCSI bus does not support a device reset operation.
874   @retval  EFI_TIMEOUT       A timeout occurred while attempting to reset the
875                              SCSI Controller.
876 **/
877 EFI_STATUS
878 EFIAPI
ScsiResetDevice(IN EFI_SCSI_IO_PROTOCOL * This)879 ScsiResetDevice (
880   IN  EFI_SCSI_IO_PROTOCOL     *This
881   )
882 {
883   SCSI_IO_DEV  *ScsiIoDevice;
884   UINT8        Target[TARGET_MAX_BYTES];
885 
886   ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
887 
888   //
889   // Report Status Code to indicate reset happens
890   //
891   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
892     EFI_PROGRESS_CODE,
893     (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET),
894     ScsiIoDevice->ScsiBusDeviceData->DevicePath
895     );
896 
897   CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);
898 
899 
900   if (ScsiIoDevice->ExtScsiSupport) {
901     return ScsiIoDevice->ExtScsiPassThru->ResetTargetLun (
902                                         ScsiIoDevice->ExtScsiPassThru,
903                                         Target,
904                                         ScsiIoDevice->Lun
905                                           );
906   } else {
907     return ScsiIoDevice->ScsiPassThru->ResetTarget (
908                                           ScsiIoDevice->ScsiPassThru,
909                                           ScsiIoDevice->Pun.ScsiId.Scsi,
910                                           ScsiIoDevice->Lun
911                                             );
912   }
913 }
914 
915 
916 /**
917   Sends a SCSI Request Packet to the SCSI Controller for execution.
918 
919   @param  This            Protocol instance pointer.
920   @param  CommandPacket   The SCSI request packet to send to the SCSI
921                           Controller specified by the device handle.
922   @param  Event           If the SCSI bus where the SCSI device is attached
923                           does not support non-blocking I/O, then Event is
924                           ignored, and blocking I/O is performed.
925                           If Event is NULL, then blocking I/O is performed.
926                           If Event is not NULL and non-blocking I/O is
927                           supported, then non-blocking I/O is performed,
928                           and Event will be signaled when the SCSI Request
929                           Packet completes.
930 
931   @retval EFI_SUCCESS         The SCSI Request Packet was sent by the host
932                               successfully, and TransferLength bytes were
933                               transferred to/from DataBuffer.See
934                               HostAdapterStatus, TargetStatus,
935                               SenseDataLength, and SenseData in that order
936                               for additional status information.
937   @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
938                               but the entire DataBuffer could not be transferred.
939                               The actual number of bytes transferred is returned
940                               in TransferLength. See HostAdapterStatus,
941                               TargetStatus, SenseDataLength, and SenseData in
942                               that order for additional status information.
943   @retval EFI_NOT_READY       The SCSI Request Packet could not be sent because
944                               there are too many SCSI Command Packets already
945                               queued.The caller may retry again later.
946   @retval EFI_DEVICE_ERROR    A device error occurred while attempting to send
947                               the SCSI Request Packet. See HostAdapterStatus,
948                               TargetStatus, SenseDataLength, and SenseData in
949                               that order for additional status information.
950   @retval EFI_INVALID_PARAMETER  The contents of CommandPacket are invalid.
951                                  The SCSI Request Packet was not sent, so no
952                                  additional status information is available.
953   @retval EFI_UNSUPPORTED     The command described by the SCSI Request Packet
954                               is not supported by the SCSI initiator(i.e., SCSI
955                               Host Controller). The SCSI Request Packet was not
956                               sent, so no additional status information is
957                               available.
958   @retval EFI_TIMEOUT         A timeout occurred while waiting for the SCSI
959                               Request Packet to execute. See HostAdapterStatus,
960                               TargetStatus, SenseDataLength, and SenseData in
961                               that order for additional status information.
962 **/
963 EFI_STATUS
964 EFIAPI
ScsiExecuteSCSICommand(IN EFI_SCSI_IO_PROTOCOL * This,IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET * Packet,IN EFI_EVENT Event OPTIONAL)965 ScsiExecuteSCSICommand (
966   IN     EFI_SCSI_IO_PROTOCOL                     *This,
967   IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET          *Packet,
968   IN     EFI_EVENT                                Event  OPTIONAL
969   )
970 {
971   SCSI_IO_DEV                                 *ScsiIoDevice;
972   EFI_STATUS                                  Status;
973   UINT8                                       Target[TARGET_MAX_BYTES];
974   EFI_EVENT                                   PacketEvent;
975   EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *ExtRequestPacket;
976   SCSI_EVENT_DATA                             EventData;
977 
978   PacketEvent = NULL;
979 
980   if (Packet == NULL) {
981     return EFI_INVALID_PARAMETER;
982   }
983 
984   ScsiIoDevice  = SCSI_IO_DEV_FROM_THIS (This);
985   CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);
986 
987   if (ScsiIoDevice->ExtScsiSupport) {
988     ExtRequestPacket = (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *) Packet;
989 
990     if (((ScsiIoDevice->ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) != 0) && (Event !=  NULL)) {
991       Status = ScsiIoDevice->ExtScsiPassThru->PassThru (
992                                                 ScsiIoDevice->ExtScsiPassThru,
993                                                 Target,
994                                                 ScsiIoDevice->Lun,
995                                                 ExtRequestPacket,
996                                                 Event
997                                                 );
998     } else {
999       //
1000       // If there's no event or the SCSI Device doesn't support NON-BLOCKING,
1001       // let the 'Event' parameter for PassThru() be NULL.
1002       //
1003       Status = ScsiIoDevice->ExtScsiPassThru->PassThru (
1004                                                 ScsiIoDevice->ExtScsiPassThru,
1005                                                 Target,
1006                                                 ScsiIoDevice->Lun,
1007                                                 ExtRequestPacket,
1008                                                 NULL
1009                                                 );
1010       if ((!EFI_ERROR(Status)) && (Event != NULL)) {
1011         //
1012         // Signal Event to tell caller to pick up the SCSI IO packet if the
1013         // PassThru() succeeds.
1014         //
1015         gBS->SignalEvent (Event);
1016       }
1017     }
1018   } else {
1019 
1020     mWorkingBuffer = AllocatePool (sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
1021 
1022     if (mWorkingBuffer == NULL) {
1023       return EFI_DEVICE_ERROR;
1024     }
1025 
1026     //
1027     // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.
1028     //
1029     Status = ScsiioToPassThruPacket(Packet, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer);
1030     if (EFI_ERROR(Status)) {
1031       FreePool(mWorkingBuffer);
1032       return Status;
1033     }
1034 
1035     if (((ScsiIoDevice->ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) != 0) && (Event !=  NULL)) {
1036       EventData.Data1 = (VOID*)Packet;
1037       EventData.Data2 = Event;
1038       //
1039       // Create Event
1040       //
1041       Status = gBS->CreateEvent (
1042                        EVT_NOTIFY_SIGNAL,
1043                        TPL_NOTIFY,
1044                        NotifyFunction,
1045                        &EventData,
1046                        &PacketEvent
1047                        );
1048       if (EFI_ERROR(Status)) {
1049         FreePool(mWorkingBuffer);
1050         return Status;
1051       }
1052 
1053       Status = ScsiIoDevice->ScsiPassThru->PassThru (
1054                                           ScsiIoDevice->ScsiPassThru,
1055                                           ScsiIoDevice->Pun.ScsiId.Scsi,
1056                                           ScsiIoDevice->Lun,
1057                                           mWorkingBuffer,
1058                                           PacketEvent
1059                                           );
1060 
1061       if (EFI_ERROR(Status)) {
1062         FreePool(mWorkingBuffer);
1063         gBS->CloseEvent(PacketEvent);
1064         return Status;
1065       }
1066 
1067     } else {
1068       //
1069       // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert
1070       // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.
1071       //
1072       Status = ScsiIoDevice->ScsiPassThru->PassThru (
1073                                           ScsiIoDevice->ScsiPassThru,
1074                                           ScsiIoDevice->Pun.ScsiId.Scsi,
1075                                           ScsiIoDevice->Lun,
1076                                           mWorkingBuffer,
1077                                           NULL
1078                                           );
1079       if (EFI_ERROR(Status)) {
1080         FreePool(mWorkingBuffer);
1081         return Status;
1082       }
1083 
1084       PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer,Packet);
1085       //
1086       // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1087       // free mWorkingBuffer.
1088       //
1089       FreePool(mWorkingBuffer);
1090 
1091       //
1092       // Signal Event to tell caller to pick up the SCSI IO Packet.
1093       //
1094       if (Event != NULL) {
1095         gBS->SignalEvent (Event);
1096       }
1097     }
1098   }
1099   return Status;
1100 }
1101 
1102 
1103 /**
1104   Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.
1105 
1106   @param  This           Protocol instance pointer
1107   @param  Controller     Controller handle
1108   @param  TargetId       Tartget to be scanned
1109   @param  Lun            The Lun of the SCSI device on the SCSI channel.
1110   @param  ScsiBusDev     The pointer of SCSI_BUS_DEVICE
1111 
1112   @retval EFI_SUCCESS           Successfully to discover the device and attach
1113                                 ScsiIoProtocol to it.
1114   @retval EFI_OUT_OF_RESOURCES  Fail to discover the device.
1115 
1116 **/
1117 EFI_STATUS
1118 EFIAPI
ScsiScanCreateDevice(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN SCSI_TARGET_ID * TargetId,IN UINT64 Lun,IN OUT SCSI_BUS_DEVICE * ScsiBusDev)1119 ScsiScanCreateDevice (
1120   IN     EFI_DRIVER_BINDING_PROTOCOL   *This,
1121   IN     EFI_HANDLE                    Controller,
1122   IN     SCSI_TARGET_ID                *TargetId,
1123   IN     UINT64                        Lun,
1124   IN OUT SCSI_BUS_DEVICE               *ScsiBusDev
1125   )
1126 {
1127   EFI_STATUS                Status;
1128   SCSI_IO_DEV               *ScsiIoDevice;
1129   EFI_DEVICE_PATH_PROTOCOL  *ScsiDevicePath;
1130   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
1131   EFI_DEVICE_PATH_PROTOCOL  *RemainingDevicePath;
1132   EFI_HANDLE                 DeviceHandle;
1133 
1134   DevicePath          = NULL;
1135   RemainingDevicePath = NULL;
1136   ScsiDevicePath      = NULL;
1137   ScsiIoDevice        = NULL;
1138 
1139   //
1140   // Build Device Path
1141   //
1142   if (ScsiBusDev->ExtScsiSupport){
1143     Status = ScsiBusDev->ExtScsiInterface->BuildDevicePath (
1144                                              ScsiBusDev->ExtScsiInterface,
1145                                              &TargetId->ScsiId.ExtScsi[0],
1146                                              Lun,
1147                                              &ScsiDevicePath
1148                                              );
1149   } else {
1150     Status = ScsiBusDev->ScsiInterface->BuildDevicePath (
1151                                           ScsiBusDev->ScsiInterface,
1152                                           TargetId->ScsiId.Scsi,
1153                                           Lun,
1154                                           &ScsiDevicePath
1155                                           );
1156   }
1157 
1158   if (EFI_ERROR(Status)) {
1159     return Status;
1160   }
1161 
1162   DevicePath = AppendDevicePathNode (
1163                  ScsiBusDev->DevicePath,
1164                  ScsiDevicePath
1165                  );
1166 
1167   if (DevicePath == NULL) {
1168     Status = EFI_OUT_OF_RESOURCES;
1169     goto ErrorExit;
1170   }
1171 
1172   DeviceHandle = NULL;
1173   RemainingDevicePath = DevicePath;
1174   Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);
1175   if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {
1176     //
1177     // The device has been started, directly return to fast boot.
1178     //
1179     Status = EFI_ALREADY_STARTED;
1180     goto ErrorExit;
1181   }
1182 
1183   ScsiIoDevice = AllocateZeroPool (sizeof (SCSI_IO_DEV));
1184   if (ScsiIoDevice == NULL) {
1185     Status = EFI_OUT_OF_RESOURCES;
1186     goto ErrorExit;
1187   }
1188 
1189   ScsiIoDevice->Signature                 = SCSI_IO_DEV_SIGNATURE;
1190   ScsiIoDevice->ScsiBusDeviceData         = ScsiBusDev;
1191   CopyMem(&ScsiIoDevice->Pun, TargetId, TARGET_MAX_BYTES);
1192   ScsiIoDevice->Lun                       = Lun;
1193 
1194   if (ScsiBusDev->ExtScsiSupport) {
1195     ScsiIoDevice->ExtScsiPassThru         = ScsiBusDev->ExtScsiInterface;
1196     ScsiIoDevice->ExtScsiSupport          = TRUE;
1197     ScsiIoDevice->ScsiIo.IoAlign          = ScsiIoDevice->ExtScsiPassThru->Mode->IoAlign;
1198 
1199   } else {
1200     ScsiIoDevice->ScsiPassThru            = ScsiBusDev->ScsiInterface;
1201     ScsiIoDevice->ExtScsiSupport          = FALSE;
1202     ScsiIoDevice->ScsiIo.IoAlign          = ScsiIoDevice->ScsiPassThru->Mode->IoAlign;
1203   }
1204 
1205   ScsiIoDevice->ScsiIo.GetDeviceType      = ScsiGetDeviceType;
1206   ScsiIoDevice->ScsiIo.GetDeviceLocation  = ScsiGetDeviceLocation;
1207   ScsiIoDevice->ScsiIo.ResetBus           = ScsiResetBus;
1208   ScsiIoDevice->ScsiIo.ResetDevice        = ScsiResetDevice;
1209   ScsiIoDevice->ScsiIo.ExecuteScsiCommand = ScsiExecuteSCSICommand;
1210 
1211   //
1212   // Report Status Code here since the new SCSI device will be discovered
1213   //
1214   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1215     EFI_PROGRESS_CODE,
1216     (EFI_IO_BUS_SCSI | EFI_IOB_PC_ENABLE),
1217     ScsiBusDev->DevicePath
1218     );
1219 
1220   if (!DiscoverScsiDevice (ScsiIoDevice)) {
1221     Status = EFI_OUT_OF_RESOURCES;
1222     goto ErrorExit;
1223   }
1224 
1225   ScsiIoDevice->DevicePath = DevicePath;
1226 
1227   Status = gBS->InstallMultipleProtocolInterfaces (
1228                   &ScsiIoDevice->Handle,
1229                   &gEfiDevicePathProtocolGuid,
1230                   ScsiIoDevice->DevicePath,
1231                   &gEfiScsiIoProtocolGuid,
1232                   &ScsiIoDevice->ScsiIo,
1233                   NULL
1234                   );
1235   if (EFI_ERROR (Status)) {
1236     goto ErrorExit;
1237   } else {
1238     if (ScsiBusDev->ExtScsiSupport) {
1239       gBS->OpenProtocol (
1240              Controller,
1241              &gEfiExtScsiPassThruProtocolGuid,
1242              (VOID **) &(ScsiBusDev->ExtScsiInterface),
1243              This->DriverBindingHandle,
1244              ScsiIoDevice->Handle,
1245              EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1246              );
1247      } else {
1248       gBS->OpenProtocol (
1249              Controller,
1250              &gEfiScsiPassThruProtocolGuid,
1251              (VOID **) &(ScsiBusDev->ScsiInterface),
1252              This->DriverBindingHandle,
1253              ScsiIoDevice->Handle,
1254              EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1255              );
1256      }
1257   }
1258   return EFI_SUCCESS;
1259 
1260 ErrorExit:
1261 
1262   //
1263   // The memory space for ScsiDevicePath is allocated in
1264   // ScsiPassThru->BuildDevicePath() function; It is no longer used
1265   // after AppendDevicePathNode,so free the memory it occupies.
1266   //
1267   FreePool (ScsiDevicePath);
1268 
1269   if (DevicePath != NULL) {
1270     FreePool (DevicePath);
1271   }
1272 
1273   if (ScsiIoDevice != NULL) {
1274     FreePool (ScsiIoDevice);
1275   }
1276 
1277   return Status;
1278 }
1279 
1280 
1281 /**
1282   Discovery SCSI Device
1283 
1284   @param  ScsiIoDevice    The pointer of SCSI_IO_DEV
1285 
1286   @retval  TRUE   Find SCSI Device and verify it.
1287   @retval  FALSE  Unable to find SCSI Device.
1288 
1289 **/
1290 BOOLEAN
DiscoverScsiDevice(IN OUT SCSI_IO_DEV * ScsiIoDevice)1291 DiscoverScsiDevice (
1292   IN OUT  SCSI_IO_DEV   *ScsiIoDevice
1293   )
1294 {
1295   EFI_STATUS            Status;
1296   UINT32                InquiryDataLength;
1297   UINT8                 SenseDataLength;
1298   UINT8                 HostAdapterStatus;
1299   UINT8                 TargetStatus;
1300   EFI_SCSI_INQUIRY_DATA *InquiryData;
1301   UINT8                 MaxRetry;
1302   UINT8                 Index;
1303   BOOLEAN               ScsiDeviceFound;
1304 
1305   HostAdapterStatus = 0;
1306   TargetStatus      = 0;
1307 
1308   InquiryData = AllocateAlignedBuffer (ScsiIoDevice, sizeof (EFI_SCSI_INQUIRY_DATA));
1309   if (InquiryData == NULL) {
1310     ScsiDeviceFound = FALSE;
1311     goto Done;
1312   }
1313 
1314   //
1315   // Using Inquiry command to scan for the device
1316   //
1317   InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
1318   SenseDataLength   = 0;
1319   ZeroMem (InquiryData, InquiryDataLength);
1320 
1321   MaxRetry = 2;
1322   for (Index = 0; Index < MaxRetry; Index++) {
1323     Status = ScsiInquiryCommand (
1324               &ScsiIoDevice->ScsiIo,
1325               SCSI_BUS_TIMEOUT,
1326               NULL,
1327               &SenseDataLength,
1328               &HostAdapterStatus,
1329               &TargetStatus,
1330               (VOID *) InquiryData,
1331               &InquiryDataLength,
1332               FALSE
1333               );
1334     if (!EFI_ERROR (Status)) {
1335       break;
1336     } else if ((Status == EFI_BAD_BUFFER_SIZE) ||
1337                (Status == EFI_INVALID_PARAMETER) ||
1338                (Status == EFI_UNSUPPORTED)) {
1339       ScsiDeviceFound = FALSE;
1340       goto Done;
1341     }
1342   }
1343 
1344   if (Index == MaxRetry) {
1345     ScsiDeviceFound = FALSE;
1346     goto Done;
1347   }
1348 
1349   //
1350   // Retrieved inquiry data successfully
1351   //
1352   if ((InquiryData->Peripheral_Qualifier != 0) &&
1353       (InquiryData->Peripheral_Qualifier != 3)) {
1354     ScsiDeviceFound = FALSE;
1355     goto Done;
1356   }
1357 
1358   if (InquiryData->Peripheral_Qualifier == 3) {
1359     if (InquiryData->Peripheral_Type != 0x1f) {
1360       ScsiDeviceFound = FALSE;
1361       goto Done;
1362     }
1363   }
1364 
1365   if (0x1e >= InquiryData->Peripheral_Type && InquiryData->Peripheral_Type >= 0xa) {
1366     ScsiDeviceFound = FALSE;
1367     goto Done;
1368   }
1369 
1370   //
1371   // valid device type and peripheral qualifier combination.
1372   //
1373   ScsiIoDevice->ScsiDeviceType  = InquiryData->Peripheral_Type;
1374   ScsiIoDevice->RemovableDevice = InquiryData->Rmb;
1375   if (InquiryData->Version == 0) {
1376     ScsiIoDevice->ScsiVersion = 0;
1377   } else {
1378     //
1379     // ANSI-approved version
1380     //
1381     ScsiIoDevice->ScsiVersion = (UINT8) (InquiryData->Version & 0x07);
1382   }
1383 
1384   ScsiDeviceFound = TRUE;
1385 
1386 Done:
1387   FreeAlignedBuffer (InquiryData, sizeof (EFI_SCSI_INQUIRY_DATA));
1388 
1389   return ScsiDeviceFound;
1390 }
1391 
1392 
1393 /**
1394   Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.
1395 
1396   @param  Packet         The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1397   @param  CommandPacket  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1398 
1399 **/
1400 EFI_STATUS
1401 EFIAPI
ScsiioToPassThruPacket(IN EFI_SCSI_IO_SCSI_REQUEST_PACKET * Packet,OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET * CommandPacket)1402 ScsiioToPassThruPacket (
1403   IN      EFI_SCSI_IO_SCSI_REQUEST_PACKET         *Packet,
1404   OUT     EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *CommandPacket
1405   )
1406 {
1407   //
1408   //EFI 1.10 doesn't support Bi-Direction Command.
1409   //
1410   if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL) {
1411     return EFI_UNSUPPORTED;
1412   }
1413 
1414   ZeroMem (CommandPacket, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
1415 
1416   CommandPacket->Timeout           = Packet->Timeout;
1417   CommandPacket->Cdb               = Packet->Cdb;
1418   CommandPacket->CdbLength         = Packet->CdbLength;
1419   CommandPacket->DataDirection     = Packet->DataDirection;
1420   CommandPacket->HostAdapterStatus = Packet->HostAdapterStatus;
1421   CommandPacket->TargetStatus      = Packet->TargetStatus;
1422   CommandPacket->SenseData         = Packet->SenseData;
1423   CommandPacket->SenseDataLength   = Packet->SenseDataLength;
1424 
1425   if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) {
1426     CommandPacket->DataBuffer = Packet->InDataBuffer;
1427     CommandPacket->TransferLength = Packet->InTransferLength;
1428   } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) {
1429     CommandPacket->DataBuffer = Packet->OutDataBuffer;
1430     CommandPacket->TransferLength = Packet->OutTransferLength;
1431   }
1432   return EFI_SUCCESS;
1433 }
1434 
1435 
1436 /**
1437   Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.
1438 
1439   @param  ScsiPacket  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1440   @param  Packet      The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1441 
1442 **/
1443 EFI_STATUS
1444 EFIAPI
PassThruToScsiioPacket(IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET * ScsiPacket,OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET * Packet)1445 PassThruToScsiioPacket (
1446   IN     EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *ScsiPacket,
1447   OUT    EFI_SCSI_IO_SCSI_REQUEST_PACKET         *Packet
1448   )
1449 {
1450   Packet->Timeout           = ScsiPacket->Timeout;
1451   Packet->Cdb               = ScsiPacket->Cdb;
1452   Packet->CdbLength         = ScsiPacket->CdbLength;
1453   Packet->DataDirection     = ScsiPacket->DataDirection;
1454   Packet->HostAdapterStatus = ScsiPacket->HostAdapterStatus;
1455   Packet->TargetStatus      = ScsiPacket->TargetStatus;
1456   Packet->SenseData         = ScsiPacket->SenseData;
1457   Packet->SenseDataLength   = ScsiPacket->SenseDataLength;
1458 
1459   if (ScsiPacket->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) {
1460     Packet->InDataBuffer = ScsiPacket->DataBuffer;
1461     Packet->InTransferLength = ScsiPacket->TransferLength;
1462   } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) {
1463     Packet->OutDataBuffer = ScsiPacket->DataBuffer;
1464     Packet->OutTransferLength = ScsiPacket->TransferLength;
1465   }
1466 
1467   return EFI_SUCCESS;
1468 }
1469 
1470 /**
1471   Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
1472   SCSI IO Packet.
1473 
1474   @param  Event    The instance of EFI_EVENT.
1475   @param  Context  The parameter passed in.
1476 
1477 **/
1478 VOID
1479 EFIAPI
NotifyFunction(IN EFI_EVENT Event,IN VOID * Context)1480 NotifyFunction (
1481   IN  EFI_EVENT  Event,
1482   IN  VOID       *Context
1483   )
1484 {
1485   EFI_SCSI_IO_SCSI_REQUEST_PACKET          *Packet;
1486   EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   *ScsiPacket;
1487   EFI_EVENT                                CallerEvent;
1488   SCSI_EVENT_DATA                          *PassData;
1489 
1490   PassData = (SCSI_EVENT_DATA*)Context;
1491   Packet  = (EFI_SCSI_IO_SCSI_REQUEST_PACKET *)PassData->Data1;
1492   ScsiPacket =  (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer;
1493 
1494   //
1495   // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.
1496   //
1497   PassThruToScsiioPacket(ScsiPacket, Packet);
1498 
1499   //
1500   // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1501   // free mWorkingBuffer.
1502   //
1503   gBS->FreePool(mWorkingBuffer);
1504 
1505   //
1506   // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.
1507   //
1508   CallerEvent = PassData->Data2;
1509   gBS->CloseEvent(Event);
1510   gBS->SignalEvent(CallerEvent);
1511 }
1512 
1513