2 SCSI Bus driver that layers on every SCSI Pass Thru and
3 Extended SCSI Pass Thru protocol in the system.
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
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.
20 EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding
= {
21 SCSIBusDriverBindingSupported
,
22 SCSIBusDriverBindingStart
,
23 SCSIBusDriverBindingStop
,
32 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.
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
40 ScsiioToPassThruPacket (
41 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
42 OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
46 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.
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
54 PassThruToScsiioPacket (
55 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
56 OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
60 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
63 @param Event The instance of EFI_EVENT.
64 @param Context The parameter passed in.
75 Allocates an aligned buffer for SCSI device.
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
81 @param ScsiIoDevice The SCSI child device involved for the operation.
82 @param BufferSize The request buffer size.
84 @return A pointer to the aligned buffer or NULL if the allocation fails.
88 AllocateAlignedBuffer (
89 IN SCSI_IO_DEV
*ScsiIoDevice
,
93 return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize
), ScsiIoDevice
->ScsiIo
.IoAlign
);
97 Frees an aligned buffer for SCSI device.
99 This function frees an aligned buffer for the SCSI device to perform
100 SCSI pass through operations.
102 @param Buffer The aligned buffer to be freed.
103 @param BufferSize The request buffer size.
112 if (Buffer
!= NULL
) {
113 FreeAlignedPages (Buffer
, EFI_SIZE_TO_PAGES (BufferSize
));
118 The user Entry Point for module ScsiBus. The user code starts with this function.
120 @param ImageHandle The firmware allocated handle for the EFI image.
121 @param SystemTable A pointer to the EFI System Table.
123 @retval EFI_SUCCESS The entry point is executed successfully.
124 @retval other Some error occurs when executing this entry point.
130 IN EFI_HANDLE ImageHandle
,
131 IN EFI_SYSTEM_TABLE
*SystemTable
137 // Install driver model protocol(s).
139 Status
= EfiLibInstallDriverBindingComponentName2 (
142 &gSCSIBusDriverBinding
,
144 &gScsiBusComponentName
,
145 &gScsiBusComponentName2
147 ASSERT_EFI_ERROR (Status
);
154 Test to see if this driver supports ControllerHandle.
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
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
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
174 SCSIBusDriverBindingSupported (
175 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
176 IN EFI_HANDLE Controller
,
177 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
181 EFI_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
182 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtPassThru
;
185 SCSI_TARGET_ID ScsiTargetId
;
187 TargetId
= &ScsiTargetId
.ScsiId
.ExtScsi
[0];
188 SetMem (TargetId
, TARGET_MAX_BYTES
, 0xFF);
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.
195 Status
= gBS
->OpenProtocol (
197 &gEfiExtScsiPassThruProtocolGuid
,
198 (VOID
**)&ExtPassThru
,
199 This
->DriverBindingHandle
,
201 EFI_OPEN_PROTOCOL_BY_DRIVER
204 if (Status
== EFI_ALREADY_STARTED
) {
206 } else if (!EFI_ERROR(Status
)) {
208 // Check if RemainingDevicePath is NULL or the End of Device Path Node,
209 // if yes, return EFI_SUCCESS.
211 if ((RemainingDevicePath
== NULL
) || IsDevicePathEnd (RemainingDevicePath
)) {
213 // Close protocol regardless of RemainingDevicePath validation
217 &gEfiExtScsiPassThruProtocolGuid
,
218 This
->DriverBindingHandle
,
224 // If RemainingDevicePath isn't the End of Device Path Node, check its validation
226 Status
= ExtPassThru
->GetTargetLun (ExtPassThru
, RemainingDevicePath
, &TargetId
, &Lun
);
228 // Close protocol regardless of RemainingDevicePath validation
232 &gEfiExtScsiPassThruProtocolGuid
,
233 This
->DriverBindingHandle
,
236 if (!EFI_ERROR(Status
)) {
243 // Come here in 2 condition:
244 // 1. ExtPassThru doesn't exist.
245 // 2. ExtPassThru exists but RemainingDevicePath is invalid.
247 Status
= gBS
->OpenProtocol (
249 &gEfiScsiPassThruProtocolGuid
,
251 This
->DriverBindingHandle
,
253 EFI_OPEN_PROTOCOL_BY_DRIVER
256 if (Status
== EFI_ALREADY_STARTED
) {
260 if (EFI_ERROR (Status
)) {
265 // Test RemainingDevicePath is valid or not.
267 if ((RemainingDevicePath
!= NULL
) && !IsDevicePathEnd (RemainingDevicePath
)) {
268 Status
= PassThru
->GetTargetLun (PassThru
, RemainingDevicePath
, &ScsiTargetId
.ScsiId
.Scsi
, &Lun
);
273 &gEfiScsiPassThruProtocolGuid
,
274 This
->DriverBindingHandle
,
282 Start this driver on ControllerHandle.
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
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
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
302 SCSIBusDriverBindingStart (
303 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
304 IN EFI_HANDLE Controller
,
305 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
310 BOOLEAN ScanOtherPuns
;
311 BOOLEAN FromFirstTarget
;
312 BOOLEAN ExtScsiSupport
;
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
;
324 ScanOtherPuns
= TRUE
;
325 FromFirstTarget
= FALSE
;
326 ExtScsiSupport
= FALSE
;
327 PassThruStatus
= EFI_SUCCESS
;
329 TargetId
= &ScsiTargetId
.ScsiId
.ExtScsi
[0];
330 SetMem (TargetId
, TARGET_MAX_BYTES
, 0xFF);
332 DevicePathStatus
= gBS
->OpenProtocol (
334 &gEfiDevicePathProtocolGuid
,
335 (VOID
**) &ParentDevicePath
,
336 This
->DriverBindingHandle
,
338 EFI_OPEN_PROTOCOL_BY_DRIVER
340 if (EFI_ERROR (DevicePathStatus
) && (DevicePathStatus
!= EFI_ALREADY_STARTED
)) {
341 return DevicePathStatus
;
345 // Report Status Code to indicate SCSI bus starts
347 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
349 (EFI_IO_BUS_SCSI
| EFI_IOB_PC_INIT
),
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.
358 Status
= gBS
->OpenProtocol (
360 &gEfiExtScsiPassThruProtocolGuid
,
361 (VOID
**) &ExtScsiInterface
,
362 This
->DriverBindingHandle
,
364 EFI_OPEN_PROTOCOL_BY_DRIVER
367 // Fail to open UEFI ExtendPassThru Protocol, then try to open EFI PassThru Protocol instead.
369 if (EFI_ERROR(Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
370 Status
= gBS
->OpenProtocol (
372 &gEfiScsiPassThruProtocolGuid
,
373 (VOID
**) &ScsiInterface
,
374 This
->DriverBindingHandle
,
376 EFI_OPEN_PROTOCOL_BY_DRIVER
379 // Fail to open EFI PassThru Protocol, Close the DevicePathProtocol if it is opened by this time.
381 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
382 if (!EFI_ERROR(DevicePathStatus
)) {
385 &gEfiDevicePathProtocolGuid
,
386 This
->DriverBindingHandle
,
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.
398 ExtScsiSupport
= TRUE
;
399 PassThruStatus
= gBS
->OpenProtocol (
401 &gEfiScsiPassThruProtocolGuid
,
402 (VOID
**) &ScsiInterface
,
403 This
->DriverBindingHandle
,
405 EFI_OPEN_PROTOCOL_BY_DRIVER
409 if (Status
!= EFI_ALREADY_STARTED
) {
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.
415 ScsiBusDev
= AllocateZeroPool(sizeof(SCSI_BUS_DEVICE
));
416 if (ScsiBusDev
== NULL
) {
417 Status
= EFI_OUT_OF_RESOURCES
;
420 ScsiBusDev
->Signature
= SCSI_BUS_DEVICE_SIGNATURE
;
421 ScsiBusDev
->ExtScsiSupport
= ExtScsiSupport
;
422 ScsiBusDev
->DevicePath
= ParentDevicePath
;
423 if (ScsiBusDev
->ExtScsiSupport
) {
424 ScsiBusDev
->ExtScsiInterface
= ExtScsiInterface
;
426 ScsiBusDev
->ScsiInterface
= ScsiInterface
;
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.
434 Status
= gBS
->InstallProtocolInterface (
437 EFI_NATIVE_INTERFACE
,
438 &ScsiBusDev
->BusIdentify
440 if (EFI_ERROR (Status
)) {
445 // Go through here means Start() is re-invoked again, nothing special is required to do except
446 // picking up Host controller private information.
448 Status
= gBS
->OpenProtocol (
451 (VOID
**) &BusIdentify
,
452 This
->DriverBindingHandle
,
454 EFI_OPEN_PROTOCOL_GET_PROTOCOL
457 if (EFI_ERROR (Status
)) {
460 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify
);
464 // Report Status Code to indicate detecting devices on bus
466 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
468 (EFI_IO_BUS_SCSI
| EFI_IOB_PC_DETECT
),
473 if (RemainingDevicePath
== NULL
) {
475 // If RemainingDevicePath is NULL,
476 // must enumerate all SCSI devices anyway
478 FromFirstTarget
= TRUE
;
479 } else if (!IsDevicePathEnd (RemainingDevicePath
)) {
481 // If RemainingDevicePath isn't the End of Device Path Node,
482 // only scan the specified device by RemainingDevicePath
484 if (ScsiBusDev
->ExtScsiSupport
) {
485 Status
= ScsiBusDev
->ExtScsiInterface
->GetTargetLun (ScsiBusDev
->ExtScsiInterface
, RemainingDevicePath
, &TargetId
, &Lun
);
487 Status
= ScsiBusDev
->ScsiInterface
->GetTargetLun (ScsiBusDev
->ScsiInterface
, RemainingDevicePath
, &ScsiTargetId
.ScsiId
.Scsi
, &Lun
);
490 if (EFI_ERROR (Status
)) {
495 // If RemainingDevicePath is the End of Device Path Node,
496 // skip enumerate any device and return EFI_SUCESSS
498 ScanOtherPuns
= FALSE
;
501 while(ScanOtherPuns
) {
502 if (FromFirstTarget
) {
504 // Remaining Device Path is NULL, scan all the possible Puns in the
507 if (ScsiBusDev
->ExtScsiSupport
) {
508 Status
= ScsiBusDev
->ExtScsiInterface
->GetNextTargetLun (ScsiBusDev
->ExtScsiInterface
, &TargetId
, &Lun
);
510 Status
= ScsiBusDev
->ScsiInterface
->GetNextDevice (ScsiBusDev
->ScsiInterface
, &ScsiTargetId
.ScsiId
.Scsi
, &Lun
);
512 if (EFI_ERROR (Status
)) {
514 // no legal Pun and Lun found any more
519 ScanOtherPuns
= FALSE
;
522 // Avoid creating handle for the host adapter.
524 if (ScsiBusDev
->ExtScsiSupport
) {
525 if ((ScsiTargetId
.ScsiId
.Scsi
) == ScsiBusDev
->ExtScsiInterface
->Mode
->AdapterId
) {
529 if ((ScsiTargetId
.ScsiId
.Scsi
) == ScsiBusDev
->ScsiInterface
->Mode
->AdapterId
) {
534 // Scan for the scsi device, if it attaches to the scsi bus,
535 // then create handle and install scsi i/o protocol.
537 Status
= ScsiScanCreateDevice (This
, Controller
, &ScsiTargetId
, Lun
, ScsiBusDev
);
543 if (ScsiBusDev
!= NULL
) {
544 FreePool (ScsiBusDev
);
547 if (ExtScsiSupport
) {
550 &gEfiExtScsiPassThruProtocolGuid
,
551 This
->DriverBindingHandle
,
554 if (!EFI_ERROR (PassThruStatus
)) {
557 &gEfiScsiPassThruProtocolGuid
,
558 This
->DriverBindingHandle
,
565 &gEfiScsiPassThruProtocolGuid
,
566 This
->DriverBindingHandle
,
574 Stop this driver on ControllerHandle.
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.
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.
588 @retval EFI_SUCCESS This driver is removed ControllerHandle
589 @retval other This driver was not removed from this device
594 SCSIBusDriverBindingStop (
595 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
596 IN EFI_HANDLE Controller
,
597 IN UINTN NumberOfChildren
,
598 IN EFI_HANDLE
*ChildHandleBuffer
602 BOOLEAN AllChildrenStopped
;
604 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
605 SCSI_IO_DEV
*ScsiIoDevice
;
607 EFI_SCSI_BUS_PROTOCOL
*Scsidentifier
;
608 SCSI_BUS_DEVICE
*ScsiBusDev
;
610 if (NumberOfChildren
== 0) {
612 // Get the SCSI_BUS_DEVICE
614 Status
= gBS
->OpenProtocol (
617 (VOID
**) &Scsidentifier
,
618 This
->DriverBindingHandle
,
620 EFI_OPEN_PROTOCOL_GET_PROTOCOL
623 if (EFI_ERROR (Status
)) {
624 return EFI_DEVICE_ERROR
;
627 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier
);
630 // Uninstall SCSI Bus Protocol
632 gBS
->UninstallProtocolInterface (
635 &ScsiBusDev
->BusIdentify
639 // Close the bus driver
641 if (ScsiBusDev
->ExtScsiSupport
) {
643 // Close ExtPassThru Protocol from this controller handle
647 &gEfiExtScsiPassThruProtocolGuid
,
648 This
->DriverBindingHandle
,
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.
658 &gEfiScsiPassThruProtocolGuid
,
659 This
->DriverBindingHandle
,
665 &gEfiScsiPassThruProtocolGuid
,
666 This
->DriverBindingHandle
,
673 &gEfiDevicePathProtocolGuid
,
674 This
->DriverBindingHandle
,
677 FreePool (ScsiBusDev
);
681 AllChildrenStopped
= TRUE
;
683 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
685 Status
= gBS
->OpenProtocol (
686 ChildHandleBuffer
[Index
],
687 &gEfiScsiIoProtocolGuid
,
689 This
->DriverBindingHandle
,
691 EFI_OPEN_PROTOCOL_GET_PROTOCOL
693 if (EFI_ERROR (Status
)) {
694 AllChildrenStopped
= FALSE
;
698 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (ScsiIo
);
700 // Close the child handle
702 if (ScsiIoDevice
->ExtScsiSupport
) {
703 Status
= gBS
->CloseProtocol (
705 &gEfiExtScsiPassThruProtocolGuid
,
706 This
->DriverBindingHandle
,
707 ChildHandleBuffer
[Index
]
711 Status
= gBS
->CloseProtocol (
713 &gEfiScsiPassThruProtocolGuid
,
714 This
->DriverBindingHandle
,
715 ChildHandleBuffer
[Index
]
719 Status
= gBS
->UninstallMultipleProtocolInterfaces (
720 ChildHandleBuffer
[Index
],
721 &gEfiDevicePathProtocolGuid
,
722 ScsiIoDevice
->DevicePath
,
723 &gEfiScsiIoProtocolGuid
,
724 &ScsiIoDevice
->ScsiIo
,
727 if (EFI_ERROR (Status
)) {
728 AllChildrenStopped
= FALSE
;
729 if (ScsiIoDevice
->ExtScsiSupport
) {
732 &gEfiExtScsiPassThruProtocolGuid
,
734 This
->DriverBindingHandle
,
735 ChildHandleBuffer
[Index
],
736 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
741 &gEfiScsiPassThruProtocolGuid
,
743 This
->DriverBindingHandle
,
744 ChildHandleBuffer
[Index
],
745 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
749 FreePool (ScsiIoDevice
);
753 if (!AllChildrenStopped
) {
754 return EFI_DEVICE_ERROR
;
762 Retrieves the device type information of the SCSI Controller.
764 @param This Protocol instance pointer.
765 @param DeviceType A pointer to the device type information retrieved from
768 @retval EFI_SUCCESS Retrieves the device type information successfully.
769 @retval EFI_INVALID_PARAMETER The DeviceType is NULL.
775 IN EFI_SCSI_IO_PROTOCOL
*This
,
776 OUT UINT8
*DeviceType
779 SCSI_IO_DEV
*ScsiIoDevice
;
781 if (DeviceType
== NULL
) {
782 return EFI_INVALID_PARAMETER
;
785 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
786 *DeviceType
= ScsiIoDevice
->ScsiDeviceType
;
792 Retrieves the device location in the SCSI channel.
794 @param This Protocol instance pointer.
795 @param Target A pointer to the Target ID of a SCSI device
797 @param Lun A pointer to the LUN of the SCSI device on
800 @retval EFI_SUCCESS Retrieves the device location successfully.
801 @retval EFI_INVALID_PARAMETER The Target or Lun is NULL.
806 ScsiGetDeviceLocation (
807 IN EFI_SCSI_IO_PROTOCOL
*This
,
808 IN OUT UINT8
**Target
,
812 SCSI_IO_DEV
*ScsiIoDevice
;
814 if (Target
== NULL
|| Lun
== NULL
) {
815 return EFI_INVALID_PARAMETER
;
818 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
820 CopyMem (*Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
822 *Lun
= ScsiIoDevice
->Lun
;
828 Resets the SCSI Bus that the SCSI Controller is attached to.
830 @param This Protocol instance pointer.
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
842 IN EFI_SCSI_IO_PROTOCOL
*This
845 SCSI_IO_DEV
*ScsiIoDevice
;
847 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
850 // Report Status Code to indicate reset happens
852 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
854 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_PC_RESET
),
855 ScsiIoDevice
->ScsiBusDeviceData
->DevicePath
858 if (ScsiIoDevice
->ExtScsiSupport
){
859 return ScsiIoDevice
->ExtScsiPassThru
->ResetChannel (ScsiIoDevice
->ExtScsiPassThru
);
861 return ScsiIoDevice
->ScsiPassThru
->ResetChannel (ScsiIoDevice
->ScsiPassThru
);
867 Resets the SCSI Controller that the device handle specifies.
869 @param This Protocol instance pointer.
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
880 IN EFI_SCSI_IO_PROTOCOL
*This
883 SCSI_IO_DEV
*ScsiIoDevice
;
884 UINT8 Target
[TARGET_MAX_BYTES
];
886 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
889 // Report Status Code to indicate reset happens
891 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
893 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_PC_RESET
),
894 ScsiIoDevice
->ScsiBusDeviceData
->DevicePath
897 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
900 if (ScsiIoDevice
->ExtScsiSupport
) {
901 return ScsiIoDevice
->ExtScsiPassThru
->ResetTargetLun (
902 ScsiIoDevice
->ExtScsiPassThru
,
907 return ScsiIoDevice
->ScsiPassThru
->ResetTarget (
908 ScsiIoDevice
->ScsiPassThru
,
909 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
917 Sends a SCSI Request Packet to the SCSI Controller for execution.
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
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
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.
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
971 SCSI_IO_DEV
*ScsiIoDevice
;
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
;
980 if (Packet
== NULL
) {
981 return EFI_INVALID_PARAMETER
;
984 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
985 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
987 if (ScsiIoDevice
->ExtScsiSupport
) {
988 ExtRequestPacket
= (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*) Packet
;
990 if (((ScsiIoDevice
->ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO
) != 0) && (Event
!= NULL
)) {
991 Status
= ScsiIoDevice
->ExtScsiPassThru
->PassThru (
992 ScsiIoDevice
->ExtScsiPassThru
,
1000 // If there's no event or the SCSI Device doesn't support NON-BLOCKING,
1001 // let the 'Event' parameter for PassThru() be NULL.
1003 Status
= ScsiIoDevice
->ExtScsiPassThru
->PassThru (
1004 ScsiIoDevice
->ExtScsiPassThru
,
1010 if (Event
!= NULL
) {
1012 // Signal Event to tell caller to pick up the SCSI IO Packet.
1014 gBS
->SignalEvent (Event
);
1019 mWorkingBuffer
= AllocatePool (sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1021 if (mWorkingBuffer
== NULL
) {
1022 return EFI_DEVICE_ERROR
;
1026 // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.
1028 Status
= ScsiioToPassThruPacket(Packet
, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)mWorkingBuffer
);
1029 if (EFI_ERROR(Status
)) {
1030 FreePool(mWorkingBuffer
);
1034 if (((ScsiIoDevice
->ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO
) != 0) && (Event
!= NULL
)) {
1035 EventData
.Data1
= (VOID
*)Packet
;
1036 EventData
.Data2
= Event
;
1040 Status
= gBS
->CreateEvent (
1047 if (EFI_ERROR(Status
)) {
1048 FreePool(mWorkingBuffer
);
1052 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
1053 ScsiIoDevice
->ScsiPassThru
,
1054 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
1060 if (EFI_ERROR(Status
)) {
1061 FreePool(mWorkingBuffer
);
1062 gBS
->CloseEvent(PacketEvent
);
1068 // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert
1069 // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.
1071 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
1072 ScsiIoDevice
->ScsiPassThru
,
1073 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
1078 if (EFI_ERROR(Status
)) {
1079 FreePool(mWorkingBuffer
);
1083 PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)mWorkingBuffer
,Packet
);
1085 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1086 // free mWorkingBuffer.
1088 FreePool(mWorkingBuffer
);
1091 // Signal Event to tell caller to pick up the SCSI IO Packet.
1093 if (Event
!= NULL
) {
1094 gBS
->SignalEvent (Event
);
1103 Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.
1105 @param This Protocol instance pointer
1106 @param Controller Controller handle
1107 @param TargetId Tartget to be scanned
1108 @param Lun The Lun of the SCSI device on the SCSI channel.
1109 @param ScsiBusDev The pointer of SCSI_BUS_DEVICE
1111 @retval EFI_SUCCESS Successfully to discover the device and attach
1112 ScsiIoProtocol to it.
1113 @retval EFI_OUT_OF_RESOURCES Fail to discover the device.
1118 ScsiScanCreateDevice (
1119 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1120 IN EFI_HANDLE Controller
,
1121 IN SCSI_TARGET_ID
*TargetId
,
1123 IN OUT SCSI_BUS_DEVICE
*ScsiBusDev
1127 SCSI_IO_DEV
*ScsiIoDevice
;
1128 EFI_DEVICE_PATH_PROTOCOL
*ScsiDevicePath
;
1129 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1130 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
1131 EFI_HANDLE DeviceHandle
;
1134 RemainingDevicePath
= NULL
;
1135 ScsiDevicePath
= NULL
;
1136 ScsiIoDevice
= NULL
;
1139 // Build Device Path
1141 if (ScsiBusDev
->ExtScsiSupport
){
1142 Status
= ScsiBusDev
->ExtScsiInterface
->BuildDevicePath (
1143 ScsiBusDev
->ExtScsiInterface
,
1144 &TargetId
->ScsiId
.ExtScsi
[0],
1149 Status
= ScsiBusDev
->ScsiInterface
->BuildDevicePath (
1150 ScsiBusDev
->ScsiInterface
,
1151 TargetId
->ScsiId
.Scsi
,
1157 if (EFI_ERROR(Status
)) {
1161 DevicePath
= AppendDevicePathNode (
1162 ScsiBusDev
->DevicePath
,
1166 if (DevicePath
== NULL
) {
1167 Status
= EFI_OUT_OF_RESOURCES
;
1171 DeviceHandle
= NULL
;
1172 RemainingDevicePath
= DevicePath
;
1173 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &RemainingDevicePath
, &DeviceHandle
);
1174 if (!EFI_ERROR (Status
) && (DeviceHandle
!= NULL
) && IsDevicePathEnd(RemainingDevicePath
)) {
1176 // The device has been started, directly return to fast boot.
1178 Status
= EFI_ALREADY_STARTED
;
1182 ScsiIoDevice
= AllocateZeroPool (sizeof (SCSI_IO_DEV
));
1183 if (ScsiIoDevice
== NULL
) {
1184 Status
= EFI_OUT_OF_RESOURCES
;
1188 ScsiIoDevice
->Signature
= SCSI_IO_DEV_SIGNATURE
;
1189 ScsiIoDevice
->ScsiBusDeviceData
= ScsiBusDev
;
1190 CopyMem(&ScsiIoDevice
->Pun
, TargetId
, TARGET_MAX_BYTES
);
1191 ScsiIoDevice
->Lun
= Lun
;
1193 if (ScsiBusDev
->ExtScsiSupport
) {
1194 ScsiIoDevice
->ExtScsiPassThru
= ScsiBusDev
->ExtScsiInterface
;
1195 ScsiIoDevice
->ExtScsiSupport
= TRUE
;
1196 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ExtScsiPassThru
->Mode
->IoAlign
;
1199 ScsiIoDevice
->ScsiPassThru
= ScsiBusDev
->ScsiInterface
;
1200 ScsiIoDevice
->ExtScsiSupport
= FALSE
;
1201 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ScsiPassThru
->Mode
->IoAlign
;
1204 ScsiIoDevice
->ScsiIo
.GetDeviceType
= ScsiGetDeviceType
;
1205 ScsiIoDevice
->ScsiIo
.GetDeviceLocation
= ScsiGetDeviceLocation
;
1206 ScsiIoDevice
->ScsiIo
.ResetBus
= ScsiResetBus
;
1207 ScsiIoDevice
->ScsiIo
.ResetDevice
= ScsiResetDevice
;
1208 ScsiIoDevice
->ScsiIo
.ExecuteScsiCommand
= ScsiExecuteSCSICommand
;
1211 // Report Status Code here since the new SCSI device will be discovered
1213 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1215 (EFI_IO_BUS_SCSI
| EFI_IOB_PC_ENABLE
),
1216 ScsiBusDev
->DevicePath
1219 if (!DiscoverScsiDevice (ScsiIoDevice
)) {
1220 Status
= EFI_OUT_OF_RESOURCES
;
1224 ScsiIoDevice
->DevicePath
= DevicePath
;
1226 Status
= gBS
->InstallMultipleProtocolInterfaces (
1227 &ScsiIoDevice
->Handle
,
1228 &gEfiDevicePathProtocolGuid
,
1229 ScsiIoDevice
->DevicePath
,
1230 &gEfiScsiIoProtocolGuid
,
1231 &ScsiIoDevice
->ScsiIo
,
1234 if (EFI_ERROR (Status
)) {
1237 if (ScsiBusDev
->ExtScsiSupport
) {
1240 &gEfiExtScsiPassThruProtocolGuid
,
1241 (VOID
**) &(ScsiBusDev
->ExtScsiInterface
),
1242 This
->DriverBindingHandle
,
1243 ScsiIoDevice
->Handle
,
1244 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1249 &gEfiScsiPassThruProtocolGuid
,
1250 (VOID
**) &(ScsiBusDev
->ScsiInterface
),
1251 This
->DriverBindingHandle
,
1252 ScsiIoDevice
->Handle
,
1253 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1262 // The memory space for ScsiDevicePath is allocated in
1263 // ScsiPassThru->BuildDevicePath() function; It is no longer used
1264 // after AppendDevicePathNode,so free the memory it occupies.
1266 FreePool (ScsiDevicePath
);
1268 if (DevicePath
!= NULL
) {
1269 FreePool (DevicePath
);
1272 if (ScsiIoDevice
!= NULL
) {
1273 FreePool (ScsiIoDevice
);
1281 Discovery SCSI Device
1283 @param ScsiIoDevice The pointer of SCSI_IO_DEV
1285 @retval TRUE Find SCSI Device and verify it.
1286 @retval FALSE Unable to find SCSI Device.
1290 DiscoverScsiDevice (
1291 IN OUT SCSI_IO_DEV
*ScsiIoDevice
1295 UINT32 InquiryDataLength
;
1296 UINT8 SenseDataLength
;
1297 UINT8 HostAdapterStatus
;
1299 EFI_SCSI_INQUIRY_DATA
*InquiryData
;
1302 BOOLEAN ScsiDeviceFound
;
1304 HostAdapterStatus
= 0;
1307 InquiryData
= AllocateAlignedBuffer (ScsiIoDevice
, sizeof (EFI_SCSI_INQUIRY_DATA
));
1308 if (InquiryData
== NULL
) {
1309 ScsiDeviceFound
= FALSE
;
1314 // Using Inquiry command to scan for the device
1316 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1317 SenseDataLength
= 0;
1318 ZeroMem (InquiryData
, InquiryDataLength
);
1321 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1322 Status
= ScsiInquiryCommand (
1323 &ScsiIoDevice
->ScsiIo
,
1329 (VOID
*) InquiryData
,
1333 if (!EFI_ERROR (Status
)) {
1335 } else if ((Status
== EFI_BAD_BUFFER_SIZE
) ||
1336 (Status
== EFI_INVALID_PARAMETER
) ||
1337 (Status
== EFI_UNSUPPORTED
)) {
1338 ScsiDeviceFound
= FALSE
;
1343 if (Index
== MaxRetry
) {
1344 ScsiDeviceFound
= FALSE
;
1349 // Retrieved inquiry data successfully
1351 if ((InquiryData
->Peripheral_Qualifier
!= 0) &&
1352 (InquiryData
->Peripheral_Qualifier
!= 3)) {
1353 ScsiDeviceFound
= FALSE
;
1357 if (InquiryData
->Peripheral_Qualifier
== 3) {
1358 if (InquiryData
->Peripheral_Type
!= 0x1f) {
1359 ScsiDeviceFound
= FALSE
;
1364 if (0x1e >= InquiryData
->Peripheral_Type
&& InquiryData
->Peripheral_Type
>= 0xa) {
1365 ScsiDeviceFound
= FALSE
;
1370 // valid device type and peripheral qualifier combination.
1372 ScsiIoDevice
->ScsiDeviceType
= InquiryData
->Peripheral_Type
;
1373 ScsiIoDevice
->RemovableDevice
= InquiryData
->Rmb
;
1374 if (InquiryData
->Version
== 0) {
1375 ScsiIoDevice
->ScsiVersion
= 0;
1378 // ANSI-approved version
1380 ScsiIoDevice
->ScsiVersion
= (UINT8
) (InquiryData
->Version
& 0x07);
1383 ScsiDeviceFound
= TRUE
;
1386 FreeAlignedBuffer (InquiryData
, sizeof (EFI_SCSI_INQUIRY_DATA
));
1388 return ScsiDeviceFound
;
1393 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.
1395 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1396 @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1401 ScsiioToPassThruPacket (
1402 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
1403 OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
1407 //EFI 1.10 doesn't support Bi-Direction Command.
1409 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL
) {
1410 return EFI_UNSUPPORTED
;
1413 ZeroMem (CommandPacket
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1415 CommandPacket
->Timeout
= Packet
->Timeout
;
1416 CommandPacket
->Cdb
= Packet
->Cdb
;
1417 CommandPacket
->CdbLength
= Packet
->CdbLength
;
1418 CommandPacket
->DataDirection
= Packet
->DataDirection
;
1419 CommandPacket
->HostAdapterStatus
= Packet
->HostAdapterStatus
;
1420 CommandPacket
->TargetStatus
= Packet
->TargetStatus
;
1421 CommandPacket
->SenseData
= Packet
->SenseData
;
1422 CommandPacket
->SenseDataLength
= Packet
->SenseDataLength
;
1424 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1425 CommandPacket
->DataBuffer
= Packet
->InDataBuffer
;
1426 CommandPacket
->TransferLength
= Packet
->InTransferLength
;
1427 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1428 CommandPacket
->DataBuffer
= Packet
->OutDataBuffer
;
1429 CommandPacket
->TransferLength
= Packet
->OutTransferLength
;
1436 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.
1438 @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1439 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1444 PassThruToScsiioPacket (
1445 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
1446 OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
1449 Packet
->Timeout
= ScsiPacket
->Timeout
;
1450 Packet
->Cdb
= ScsiPacket
->Cdb
;
1451 Packet
->CdbLength
= ScsiPacket
->CdbLength
;
1452 Packet
->DataDirection
= ScsiPacket
->DataDirection
;
1453 Packet
->HostAdapterStatus
= ScsiPacket
->HostAdapterStatus
;
1454 Packet
->TargetStatus
= ScsiPacket
->TargetStatus
;
1455 Packet
->SenseData
= ScsiPacket
->SenseData
;
1456 Packet
->SenseDataLength
= ScsiPacket
->SenseDataLength
;
1458 if (ScsiPacket
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1459 Packet
->InDataBuffer
= ScsiPacket
->DataBuffer
;
1460 Packet
->InTransferLength
= ScsiPacket
->TransferLength
;
1461 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1462 Packet
->OutDataBuffer
= ScsiPacket
->DataBuffer
;
1463 Packet
->OutTransferLength
= ScsiPacket
->TransferLength
;
1470 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
1473 @param Event The instance of EFI_EVENT.
1474 @param Context The parameter passed in.
1484 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
;
1485 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
;
1486 EFI_EVENT CallerEvent
;
1487 SCSI_EVENT_DATA
*PassData
;
1489 PassData
= (SCSI_EVENT_DATA
*)Context
;
1490 Packet
= (EFI_SCSI_IO_SCSI_REQUEST_PACKET
*)PassData
->Data1
;
1491 ScsiPacket
= (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)mWorkingBuffer
;
1494 // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.
1496 PassThruToScsiioPacket(ScsiPacket
, Packet
);
1499 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1500 // free mWorkingBuffer.
1502 gBS
->FreePool(mWorkingBuffer
);
1505 // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.
1507 CallerEvent
= PassData
->Data2
;
1508 gBS
->CloseEvent(Event
);
1509 gBS
->SignalEvent(CallerEvent
);