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 - 2019, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
12 EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding
= {
13 SCSIBusDriverBindingSupported
,
14 SCSIBusDriverBindingStart
,
15 SCSIBusDriverBindingStop
,
24 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.
26 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
27 @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
32 ScsiioToPassThruPacket (
33 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
34 OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
38 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.
40 @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
41 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
46 PassThruToScsiioPacket (
47 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
48 OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
52 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
55 @param Event The instance of EFI_EVENT.
56 @param Context The parameter passed in.
67 Allocates an aligned buffer for SCSI device.
69 This function allocates an aligned buffer for the SCSI device to perform
70 SCSI pass through operations. The alignment requirement is from SCSI pass
73 @param ScsiIoDevice The SCSI child device involved for the operation.
74 @param BufferSize The request buffer size.
76 @return A pointer to the aligned buffer or NULL if the allocation fails.
80 AllocateAlignedBuffer (
81 IN SCSI_IO_DEV
*ScsiIoDevice
,
85 return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize
), ScsiIoDevice
->ScsiIo
.IoAlign
);
89 Frees an aligned buffer for SCSI device.
91 This function frees an aligned buffer for the SCSI device to perform
92 SCSI pass through operations.
94 @param Buffer The aligned buffer to be freed.
95 @param BufferSize The request buffer size.
104 if (Buffer
!= NULL
) {
105 FreeAlignedPages (Buffer
, EFI_SIZE_TO_PAGES (BufferSize
));
110 The user Entry Point for module ScsiBus. The user code starts with this function.
112 @param ImageHandle The firmware allocated handle for the EFI image.
113 @param SystemTable A pointer to the EFI System Table.
115 @retval EFI_SUCCESS The entry point is executed successfully.
116 @retval other Some error occurs when executing this entry point.
122 IN EFI_HANDLE ImageHandle
,
123 IN EFI_SYSTEM_TABLE
*SystemTable
129 // Install driver model protocol(s).
131 Status
= EfiLibInstallDriverBindingComponentName2 (
134 &gSCSIBusDriverBinding
,
136 &gScsiBusComponentName
,
137 &gScsiBusComponentName2
139 ASSERT_EFI_ERROR (Status
);
145 Test to see if this driver supports ControllerHandle.
147 This service is called by the EFI boot service ConnectController(). In order
148 to make drivers as small as possible, there are a few calling restrictions for
149 this service. ConnectController() must follow these calling restrictions. If
150 any other agent wishes to call Supported() it must also follow these calling
153 @param This Protocol instance pointer.
154 @param ControllerHandle Handle of device to test
155 @param RemainingDevicePath Optional parameter use to pick a specific child
158 @retval EFI_SUCCESS This driver supports this device
159 @retval EFI_ALREADY_STARTED This driver is already running on this device
160 @retval other This driver does not support this device
165 SCSIBusDriverBindingSupported (
166 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
167 IN EFI_HANDLE Controller
,
168 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
172 EFI_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
173 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtPassThru
;
176 SCSI_TARGET_ID ScsiTargetId
;
178 TargetId
= &ScsiTargetId
.ScsiId
.ExtScsi
[0];
179 SetMem (TargetId
, TARGET_MAX_BYTES
, 0xFF);
182 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
183 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
184 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
186 Status
= gBS
->OpenProtocol (
188 &gEfiExtScsiPassThruProtocolGuid
,
189 (VOID
**)&ExtPassThru
,
190 This
->DriverBindingHandle
,
192 EFI_OPEN_PROTOCOL_BY_DRIVER
195 if (Status
== EFI_ALREADY_STARTED
) {
197 } else if (!EFI_ERROR (Status
)) {
199 // Check if RemainingDevicePath is NULL or the End of Device Path Node,
200 // if yes, return EFI_SUCCESS.
202 if ((RemainingDevicePath
== NULL
) || IsDevicePathEnd (RemainingDevicePath
)) {
204 // Close protocol regardless of RemainingDevicePath validation
208 &gEfiExtScsiPassThruProtocolGuid
,
209 This
->DriverBindingHandle
,
215 // If RemainingDevicePath isn't the End of Device Path Node, check its validation
217 Status
= ExtPassThru
->GetTargetLun (ExtPassThru
, RemainingDevicePath
, &TargetId
, &Lun
);
219 // Close protocol regardless of RemainingDevicePath validation
223 &gEfiExtScsiPassThruProtocolGuid
,
224 This
->DriverBindingHandle
,
227 if (!EFI_ERROR (Status
)) {
234 // Come here in 2 condition:
235 // 1. ExtPassThru doesn't exist.
236 // 2. ExtPassThru exists but RemainingDevicePath is invalid.
238 Status
= gBS
->OpenProtocol (
240 &gEfiScsiPassThruProtocolGuid
,
242 This
->DriverBindingHandle
,
244 EFI_OPEN_PROTOCOL_BY_DRIVER
247 if (Status
== EFI_ALREADY_STARTED
) {
251 if (EFI_ERROR (Status
)) {
256 // Test RemainingDevicePath is valid or not.
258 if ((RemainingDevicePath
!= NULL
) && !IsDevicePathEnd (RemainingDevicePath
)) {
259 Status
= PassThru
->GetTargetLun (PassThru
, RemainingDevicePath
, &ScsiTargetId
.ScsiId
.Scsi
, &Lun
);
264 &gEfiScsiPassThruProtocolGuid
,
265 This
->DriverBindingHandle
,
272 Start this driver on ControllerHandle.
274 This service is called by the EFI boot service ConnectController(). In order
275 to make drivers as small as possible, there are a few calling restrictions for
276 this service. ConnectController() must follow these calling restrictions. If
277 any other agent wishes to call Start() it must also follow these calling
280 @param This Protocol instance pointer.
281 @param ControllerHandle Handle of device to bind driver to
282 @param RemainingDevicePath Optional parameter use to pick a specific child
285 @retval EFI_SUCCESS This driver is added to ControllerHandle
286 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
287 @retval other This driver does not support this device
292 SCSIBusDriverBindingStart (
293 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
294 IN EFI_HANDLE Controller
,
295 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
300 BOOLEAN ScanOtherPuns
;
301 BOOLEAN FromFirstTarget
;
302 BOOLEAN ExtScsiSupport
;
304 EFI_STATUS DevicePathStatus
;
305 EFI_STATUS PassThruStatus
;
306 SCSI_BUS_DEVICE
*ScsiBusDev
;
307 SCSI_TARGET_ID ScsiTargetId
;
308 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
309 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiInterface
;
310 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiInterface
;
311 EFI_SCSI_BUS_PROTOCOL
*BusIdentify
;
314 ScanOtherPuns
= TRUE
;
315 FromFirstTarget
= FALSE
;
316 ExtScsiSupport
= FALSE
;
317 PassThruStatus
= EFI_SUCCESS
;
319 TargetId
= &ScsiTargetId
.ScsiId
.ExtScsi
[0];
320 SetMem (TargetId
, TARGET_MAX_BYTES
, 0xFF);
322 DevicePathStatus
= gBS
->OpenProtocol (
324 &gEfiDevicePathProtocolGuid
,
325 (VOID
**)&ParentDevicePath
,
326 This
->DriverBindingHandle
,
328 EFI_OPEN_PROTOCOL_BY_DRIVER
330 if (EFI_ERROR (DevicePathStatus
) && (DevicePathStatus
!= EFI_ALREADY_STARTED
)) {
331 return DevicePathStatus
;
335 // Report Status Code to indicate SCSI bus starts
337 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
339 (EFI_IO_BUS_SCSI
| EFI_IOB_PC_INIT
),
344 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
345 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
346 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
348 Status
= gBS
->OpenProtocol (
350 &gEfiExtScsiPassThruProtocolGuid
,
351 (VOID
**)&ExtScsiInterface
,
352 This
->DriverBindingHandle
,
354 EFI_OPEN_PROTOCOL_BY_DRIVER
357 // Fail to open UEFI ExtendPassThru Protocol, then try to open EFI PassThru Protocol instead.
359 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
360 Status
= gBS
->OpenProtocol (
362 &gEfiScsiPassThruProtocolGuid
,
363 (VOID
**)&ScsiInterface
,
364 This
->DriverBindingHandle
,
366 EFI_OPEN_PROTOCOL_BY_DRIVER
369 // Fail to open EFI PassThru Protocol, Close the DevicePathProtocol if it is opened by this time.
371 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
372 if (!EFI_ERROR (DevicePathStatus
)) {
375 &gEfiDevicePathProtocolGuid
,
376 This
->DriverBindingHandle
,
385 // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol
386 // with BY_DRIVER if it is also present on the handle. The intent is to prevent
387 // another SCSI Bus Driver to work on the same host handle.
389 ExtScsiSupport
= TRUE
;
390 PassThruStatus
= gBS
->OpenProtocol (
392 &gEfiScsiPassThruProtocolGuid
,
393 (VOID
**)&ScsiInterface
,
394 This
->DriverBindingHandle
,
396 EFI_OPEN_PROTOCOL_BY_DRIVER
400 if (Status
!= EFI_ALREADY_STARTED
) {
402 // Go through here means either ExtPassThru or PassThru Protocol is successfully opened
403 // on this handle for this time. Then construct Host controller private data.
406 ScsiBusDev
= AllocateZeroPool (sizeof (SCSI_BUS_DEVICE
));
407 if (ScsiBusDev
== NULL
) {
408 Status
= EFI_OUT_OF_RESOURCES
;
412 ScsiBusDev
->Signature
= SCSI_BUS_DEVICE_SIGNATURE
;
413 ScsiBusDev
->ExtScsiSupport
= ExtScsiSupport
;
414 ScsiBusDev
->DevicePath
= ParentDevicePath
;
415 if (ScsiBusDev
->ExtScsiSupport
) {
416 ScsiBusDev
->ExtScsiInterface
= ExtScsiInterface
;
418 ScsiBusDev
->ScsiInterface
= ScsiInterface
;
422 // Install EFI_SCSI_BUS_PROTOCOL to the controller handle, So ScsiBusDev could be
423 // retrieved on this controller handle. With ScsiBusDev, we can know which PassThru
424 // Protocol is present on the handle, UEFI ExtPassThru Protocol or EFI PassThru Protocol.
426 Status
= gBS
->InstallProtocolInterface (
429 EFI_NATIVE_INTERFACE
,
430 &ScsiBusDev
->BusIdentify
432 if (EFI_ERROR (Status
)) {
437 // Go through here means Start() is re-invoked again, nothing special is required to do except
438 // picking up Host controller private information.
440 Status
= gBS
->OpenProtocol (
443 (VOID
**)&BusIdentify
,
444 This
->DriverBindingHandle
,
446 EFI_OPEN_PROTOCOL_GET_PROTOCOL
449 if (EFI_ERROR (Status
)) {
453 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify
);
457 // Report Status Code to indicate detecting devices on bus
459 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
461 (EFI_IO_BUS_SCSI
| EFI_IOB_PC_DETECT
),
466 if (RemainingDevicePath
== NULL
) {
468 // If RemainingDevicePath is NULL,
469 // must enumerate all SCSI devices anyway
471 FromFirstTarget
= TRUE
;
472 } else if (!IsDevicePathEnd (RemainingDevicePath
)) {
474 // If RemainingDevicePath isn't the End of Device Path Node,
475 // only scan the specified device by RemainingDevicePath
477 if (ScsiBusDev
->ExtScsiSupport
) {
478 Status
= ScsiBusDev
->ExtScsiInterface
->GetTargetLun (ScsiBusDev
->ExtScsiInterface
, RemainingDevicePath
, &TargetId
, &Lun
);
480 Status
= ScsiBusDev
->ScsiInterface
->GetTargetLun (ScsiBusDev
->ScsiInterface
, RemainingDevicePath
, &ScsiTargetId
.ScsiId
.Scsi
, &Lun
);
483 if (EFI_ERROR (Status
)) {
488 // If RemainingDevicePath is the End of Device Path Node,
489 // skip enumerate any device and return EFI_SUCCESS
491 ScanOtherPuns
= FALSE
;
494 while (ScanOtherPuns
) {
495 if (FromFirstTarget
) {
497 // Remaining Device Path is NULL, scan all the possible Puns in the
500 if (ScsiBusDev
->ExtScsiSupport
) {
501 Status
= ScsiBusDev
->ExtScsiInterface
->GetNextTargetLun (ScsiBusDev
->ExtScsiInterface
, &TargetId
, &Lun
);
503 Status
= ScsiBusDev
->ScsiInterface
->GetNextDevice (ScsiBusDev
->ScsiInterface
, &ScsiTargetId
.ScsiId
.Scsi
, &Lun
);
506 if (EFI_ERROR (Status
)) {
508 // no legal Pun and Lun found any more
513 ScanOtherPuns
= FALSE
;
517 // Avoid creating handle for the host adapter.
519 if (ScsiBusDev
->ExtScsiSupport
) {
520 if ((ScsiTargetId
.ScsiId
.Scsi
) == ScsiBusDev
->ExtScsiInterface
->Mode
->AdapterId
) {
524 if ((ScsiTargetId
.ScsiId
.Scsi
) == ScsiBusDev
->ScsiInterface
->Mode
->AdapterId
) {
530 // Scan for the scsi device, if it attaches to the scsi bus,
531 // then create handle and install scsi i/o protocol.
533 Status
= ScsiScanCreateDevice (This
, Controller
, &ScsiTargetId
, Lun
, ScsiBusDev
);
540 if (ScsiBusDev
!= NULL
) {
541 FreePool (ScsiBusDev
);
544 if (ExtScsiSupport
) {
547 &gEfiExtScsiPassThruProtocolGuid
,
548 This
->DriverBindingHandle
,
551 if (!EFI_ERROR (PassThruStatus
)) {
554 &gEfiScsiPassThruProtocolGuid
,
555 This
->DriverBindingHandle
,
562 &gEfiScsiPassThruProtocolGuid
,
563 This
->DriverBindingHandle
,
572 Stop this driver on ControllerHandle.
574 This service is called by the EFI boot service DisconnectController().
575 In order to make drivers as small as possible, there are a few calling
576 restrictions for this service. DisconnectController() must follow these
577 calling restrictions. If any other agent wishes to call Stop() it must also
578 follow these calling restrictions.
580 @param This Protocol instance pointer.
581 @param ControllerHandle Handle of device to stop driver on
582 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
583 children is zero stop the entire bus driver.
584 @param ChildHandleBuffer List of Child Handles to Stop.
586 @retval EFI_SUCCESS This driver is removed ControllerHandle
587 @retval other This driver was not removed from this device
592 SCSIBusDriverBindingStop (
593 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
594 IN EFI_HANDLE Controller
,
595 IN UINTN NumberOfChildren
,
596 IN EFI_HANDLE
*ChildHandleBuffer
600 BOOLEAN AllChildrenStopped
;
602 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
603 SCSI_IO_DEV
*ScsiIoDevice
;
605 EFI_SCSI_BUS_PROTOCOL
*Scsidentifier
;
606 SCSI_BUS_DEVICE
*ScsiBusDev
;
608 if (NumberOfChildren
== 0) {
610 // Get the SCSI_BUS_DEVICE
612 Status
= gBS
->OpenProtocol (
615 (VOID
**)&Scsidentifier
,
616 This
->DriverBindingHandle
,
618 EFI_OPEN_PROTOCOL_GET_PROTOCOL
621 if (EFI_ERROR (Status
)) {
622 return EFI_DEVICE_ERROR
;
625 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier
);
628 // Uninstall SCSI Bus Protocol
630 gBS
->UninstallProtocolInterface (
633 &ScsiBusDev
->BusIdentify
637 // Close the bus driver
639 if (ScsiBusDev
->ExtScsiSupport
) {
641 // Close ExtPassThru Protocol from this controller handle
645 &gEfiExtScsiPassThruProtocolGuid
,
646 This
->DriverBindingHandle
,
650 // When Start() succeeds to open ExtPassThru, it always tries to open PassThru BY_DRIVER.
651 // Its intent is to prevent another SCSI Bus Driver from working on the same host handle.
652 // So Stop() needs to try to close PassThru if present here.
656 &gEfiScsiPassThruProtocolGuid
,
657 This
->DriverBindingHandle
,
663 &gEfiScsiPassThruProtocolGuid
,
664 This
->DriverBindingHandle
,
671 &gEfiDevicePathProtocolGuid
,
672 This
->DriverBindingHandle
,
675 FreePool (ScsiBusDev
);
679 AllChildrenStopped
= TRUE
;
681 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
682 Status
= gBS
->OpenProtocol (
683 ChildHandleBuffer
[Index
],
684 &gEfiScsiIoProtocolGuid
,
686 This
->DriverBindingHandle
,
688 EFI_OPEN_PROTOCOL_GET_PROTOCOL
690 if (EFI_ERROR (Status
)) {
691 AllChildrenStopped
= FALSE
;
695 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (ScsiIo
);
697 // Close the child handle
699 if (ScsiIoDevice
->ExtScsiSupport
) {
700 Status
= gBS
->CloseProtocol (
702 &gEfiExtScsiPassThruProtocolGuid
,
703 This
->DriverBindingHandle
,
704 ChildHandleBuffer
[Index
]
707 Status
= gBS
->CloseProtocol (
709 &gEfiScsiPassThruProtocolGuid
,
710 This
->DriverBindingHandle
,
711 ChildHandleBuffer
[Index
]
715 Status
= gBS
->UninstallMultipleProtocolInterfaces (
716 ChildHandleBuffer
[Index
],
717 &gEfiDevicePathProtocolGuid
,
718 ScsiIoDevice
->DevicePath
,
719 &gEfiScsiIoProtocolGuid
,
720 &ScsiIoDevice
->ScsiIo
,
723 if (EFI_ERROR (Status
)) {
724 AllChildrenStopped
= FALSE
;
725 if (ScsiIoDevice
->ExtScsiSupport
) {
728 &gEfiExtScsiPassThruProtocolGuid
,
730 This
->DriverBindingHandle
,
731 ChildHandleBuffer
[Index
],
732 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
737 &gEfiScsiPassThruProtocolGuid
,
739 This
->DriverBindingHandle
,
740 ChildHandleBuffer
[Index
],
741 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
745 FreePool (ScsiIoDevice
);
749 if (!AllChildrenStopped
) {
750 return EFI_DEVICE_ERROR
;
757 Retrieves the device type information of the SCSI Controller.
759 @param This Protocol instance pointer.
760 @param DeviceType A pointer to the device type information retrieved from
763 @retval EFI_SUCCESS Retrieves the device type information successfully.
764 @retval EFI_INVALID_PARAMETER The DeviceType is NULL.
770 IN EFI_SCSI_IO_PROTOCOL
*This
,
771 OUT UINT8
*DeviceType
774 SCSI_IO_DEV
*ScsiIoDevice
;
776 if (DeviceType
== NULL
) {
777 return EFI_INVALID_PARAMETER
;
780 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
781 *DeviceType
= ScsiIoDevice
->ScsiDeviceType
;
786 Retrieves the device location in the SCSI channel.
788 @param This Protocol instance pointer.
789 @param Target A pointer to the Target ID of a SCSI device
791 @param Lun A pointer to the LUN of the SCSI device on
794 @retval EFI_SUCCESS Retrieves the device location successfully.
795 @retval EFI_INVALID_PARAMETER The Target or Lun is NULL.
800 ScsiGetDeviceLocation (
801 IN EFI_SCSI_IO_PROTOCOL
*This
,
802 IN OUT UINT8
**Target
,
806 SCSI_IO_DEV
*ScsiIoDevice
;
808 if ((Target
== NULL
) || (Lun
== NULL
)) {
809 return EFI_INVALID_PARAMETER
;
812 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
814 CopyMem (*Target
, &ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
816 *Lun
= ScsiIoDevice
->Lun
;
822 Resets the SCSI Bus that the SCSI Controller is attached to.
824 @param This Protocol instance pointer.
826 @retval EFI_SUCCESS The SCSI bus is reset successfully.
827 @retval EFI_DEVICE_ERROR Errors encountered when resetting the SCSI bus.
828 @retval EFI_UNSUPPORTED The bus reset operation is not supported by the
829 SCSI Host Controller.
830 @retval EFI_TIMEOUT A timeout occurred while attempting to reset
836 IN EFI_SCSI_IO_PROTOCOL
*This
839 SCSI_IO_DEV
*ScsiIoDevice
;
841 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
844 // Report Status Code to indicate reset happens
846 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
848 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_PC_RESET
),
849 ScsiIoDevice
->ScsiBusDeviceData
->DevicePath
852 if (ScsiIoDevice
->ExtScsiSupport
) {
853 return ScsiIoDevice
->ExtScsiPassThru
->ResetChannel (ScsiIoDevice
->ExtScsiPassThru
);
855 return ScsiIoDevice
->ScsiPassThru
->ResetChannel (ScsiIoDevice
->ScsiPassThru
);
860 Resets the SCSI Controller that the device handle specifies.
862 @param This Protocol instance pointer.
864 @retval EFI_SUCCESS Reset the SCSI controller successfully.
865 @retval EFI_DEVICE_ERROR Errors are encountered when resetting the SCSI Controller.
866 @retval EFI_UNSUPPORTED The SCSI bus does not support a device reset operation.
867 @retval EFI_TIMEOUT A timeout occurred while attempting to reset the
873 IN EFI_SCSI_IO_PROTOCOL
*This
876 SCSI_IO_DEV
*ScsiIoDevice
;
877 UINT8 Target
[TARGET_MAX_BYTES
];
879 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
882 // Report Status Code to indicate reset happens
884 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
886 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_PC_RESET
),
887 ScsiIoDevice
->ScsiBusDeviceData
->DevicePath
890 CopyMem (Target
, &ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
892 if (ScsiIoDevice
->ExtScsiSupport
) {
893 return ScsiIoDevice
->ExtScsiPassThru
->ResetTargetLun (
894 ScsiIoDevice
->ExtScsiPassThru
,
899 return ScsiIoDevice
->ScsiPassThru
->ResetTarget (
900 ScsiIoDevice
->ScsiPassThru
,
901 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
908 Sends a SCSI Request Packet to the SCSI Controller for execution.
910 @param This Protocol instance pointer.
911 @param CommandPacket The SCSI request packet to send to the SCSI
912 Controller specified by the device handle.
913 @param Event If the SCSI bus where the SCSI device is attached
914 does not support non-blocking I/O, then Event is
915 ignored, and blocking I/O is performed.
916 If Event is NULL, then blocking I/O is performed.
917 If Event is not NULL and non-blocking I/O is
918 supported, then non-blocking I/O is performed,
919 and Event will be signaled when the SCSI Request
922 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host
923 successfully, and TransferLength bytes were
924 transferred to/from DataBuffer.See
925 HostAdapterStatus, TargetStatus,
926 SenseDataLength, and SenseData in that order
927 for additional status information.
928 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
929 but the entire DataBuffer could not be transferred.
930 The actual number of bytes transferred is returned
931 in TransferLength. See HostAdapterStatus,
932 TargetStatus, SenseDataLength, and SenseData in
933 that order for additional status information.
934 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
935 there are too many SCSI Command Packets already
936 queued.The caller may retry again later.
937 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
938 the SCSI Request Packet. See HostAdapterStatus,
939 TargetStatus, SenseDataLength, and SenseData in
940 that order for additional status information.
941 @retval EFI_INVALID_PARAMETER The contents of CommandPacket are invalid.
942 The SCSI Request Packet was not sent, so no
943 additional status information is available.
944 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
945 is not supported by the SCSI initiator(i.e., SCSI
946 Host Controller). The SCSI Request Packet was not
947 sent, so no additional status information is
949 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
950 Request Packet to execute. See HostAdapterStatus,
951 TargetStatus, SenseDataLength, and SenseData in
952 that order for additional status information.
956 ScsiExecuteSCSICommand (
957 IN EFI_SCSI_IO_PROTOCOL
*This
,
958 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
959 IN EFI_EVENT Event OPTIONAL
962 SCSI_IO_DEV
*ScsiIoDevice
;
964 UINT8 Target
[TARGET_MAX_BYTES
];
965 EFI_EVENT PacketEvent
;
966 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ExtRequestPacket
;
967 SCSI_EVENT_DATA EventData
;
971 if (Packet
== NULL
) {
972 return EFI_INVALID_PARAMETER
;
975 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
976 CopyMem (Target
, &ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
978 if (ScsiIoDevice
->ExtScsiSupport
) {
979 ExtRequestPacket
= (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)Packet
;
981 if (((ScsiIoDevice
->ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO
) != 0) && (Event
!= NULL
)) {
982 Status
= ScsiIoDevice
->ExtScsiPassThru
->PassThru (
983 ScsiIoDevice
->ExtScsiPassThru
,
991 // If there's no event or the SCSI Device doesn't support NON-BLOCKING,
992 // let the 'Event' parameter for PassThru() be NULL.
994 Status
= ScsiIoDevice
->ExtScsiPassThru
->PassThru (
995 ScsiIoDevice
->ExtScsiPassThru
,
1001 if ((!EFI_ERROR (Status
)) && (Event
!= NULL
)) {
1003 // Signal Event to tell caller to pick up the SCSI IO packet if the
1004 // PassThru() succeeds.
1006 gBS
->SignalEvent (Event
);
1010 mWorkingBuffer
= AllocatePool (sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1012 if (mWorkingBuffer
== NULL
) {
1013 return EFI_DEVICE_ERROR
;
1017 // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.
1019 Status
= ScsiioToPassThruPacket (Packet
, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)mWorkingBuffer
);
1020 if (EFI_ERROR (Status
)) {
1021 FreePool (mWorkingBuffer
);
1025 if (((ScsiIoDevice
->ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO
) != 0) && (Event
!= NULL
)) {
1026 EventData
.Data1
= (VOID
*)Packet
;
1027 EventData
.Data2
= Event
;
1031 Status
= gBS
->CreateEvent (
1038 if (EFI_ERROR (Status
)) {
1039 FreePool (mWorkingBuffer
);
1043 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
1044 ScsiIoDevice
->ScsiPassThru
,
1045 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
1051 if (EFI_ERROR (Status
)) {
1052 FreePool (mWorkingBuffer
);
1053 gBS
->CloseEvent (PacketEvent
);
1058 // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert
1059 // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.
1061 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
1062 ScsiIoDevice
->ScsiPassThru
,
1063 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
1068 if (EFI_ERROR (Status
)) {
1069 FreePool (mWorkingBuffer
);
1073 PassThruToScsiioPacket ((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)mWorkingBuffer
, Packet
);
1075 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1076 // free mWorkingBuffer.
1078 FreePool (mWorkingBuffer
);
1081 // Signal Event to tell caller to pick up the SCSI IO Packet.
1083 if (Event
!= NULL
) {
1084 gBS
->SignalEvent (Event
);
1093 Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.
1095 @param This Protocol instance pointer
1096 @param Controller Controller handle
1097 @param TargetId Target to be scanned
1098 @param Lun The Lun of the SCSI device on the SCSI channel.
1099 @param ScsiBusDev The pointer of SCSI_BUS_DEVICE
1101 @retval EFI_SUCCESS Successfully to discover the device and attach
1102 ScsiIoProtocol to it.
1103 @retval EFI_OUT_OF_RESOURCES Fail to discover the device.
1108 ScsiScanCreateDevice (
1109 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1110 IN EFI_HANDLE Controller
,
1111 IN SCSI_TARGET_ID
*TargetId
,
1113 IN OUT SCSI_BUS_DEVICE
*ScsiBusDev
1117 SCSI_IO_DEV
*ScsiIoDevice
;
1118 EFI_DEVICE_PATH_PROTOCOL
*ScsiDevicePath
;
1119 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1120 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
1121 EFI_HANDLE DeviceHandle
;
1124 RemainingDevicePath
= NULL
;
1125 ScsiDevicePath
= NULL
;
1126 ScsiIoDevice
= NULL
;
1129 // Build Device Path
1131 if (ScsiBusDev
->ExtScsiSupport
) {
1132 Status
= ScsiBusDev
->ExtScsiInterface
->BuildDevicePath (
1133 ScsiBusDev
->ExtScsiInterface
,
1134 &TargetId
->ScsiId
.ExtScsi
[0],
1139 Status
= ScsiBusDev
->ScsiInterface
->BuildDevicePath (
1140 ScsiBusDev
->ScsiInterface
,
1141 TargetId
->ScsiId
.Scsi
,
1147 if (EFI_ERROR (Status
)) {
1151 DevicePath
= AppendDevicePathNode (
1152 ScsiBusDev
->DevicePath
,
1156 if (DevicePath
== NULL
) {
1157 Status
= EFI_OUT_OF_RESOURCES
;
1161 DeviceHandle
= NULL
;
1162 RemainingDevicePath
= DevicePath
;
1163 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &RemainingDevicePath
, &DeviceHandle
);
1164 if (!EFI_ERROR (Status
) && (DeviceHandle
!= NULL
) && IsDevicePathEnd (RemainingDevicePath
)) {
1166 // The device has been started, directly return to fast boot.
1168 Status
= EFI_ALREADY_STARTED
;
1172 ScsiIoDevice
= AllocateZeroPool (sizeof (SCSI_IO_DEV
));
1173 if (ScsiIoDevice
== NULL
) {
1174 Status
= EFI_OUT_OF_RESOURCES
;
1178 ScsiIoDevice
->Signature
= SCSI_IO_DEV_SIGNATURE
;
1179 ScsiIoDevice
->ScsiBusDeviceData
= ScsiBusDev
;
1180 CopyMem (&ScsiIoDevice
->Pun
, TargetId
, TARGET_MAX_BYTES
);
1181 ScsiIoDevice
->Lun
= Lun
;
1183 if (ScsiBusDev
->ExtScsiSupport
) {
1184 ScsiIoDevice
->ExtScsiPassThru
= ScsiBusDev
->ExtScsiInterface
;
1185 ScsiIoDevice
->ExtScsiSupport
= TRUE
;
1186 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ExtScsiPassThru
->Mode
->IoAlign
;
1188 ScsiIoDevice
->ScsiPassThru
= ScsiBusDev
->ScsiInterface
;
1189 ScsiIoDevice
->ExtScsiSupport
= FALSE
;
1190 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ScsiPassThru
->Mode
->IoAlign
;
1193 ScsiIoDevice
->ScsiIo
.GetDeviceType
= ScsiGetDeviceType
;
1194 ScsiIoDevice
->ScsiIo
.GetDeviceLocation
= ScsiGetDeviceLocation
;
1195 ScsiIoDevice
->ScsiIo
.ResetBus
= ScsiResetBus
;
1196 ScsiIoDevice
->ScsiIo
.ResetDevice
= ScsiResetDevice
;
1197 ScsiIoDevice
->ScsiIo
.ExecuteScsiCommand
= ScsiExecuteSCSICommand
;
1200 // Report Status Code here since the new SCSI device will be discovered
1202 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1204 (EFI_IO_BUS_SCSI
| EFI_IOB_PC_ENABLE
),
1205 ScsiBusDev
->DevicePath
1208 if (!DiscoverScsiDevice (ScsiIoDevice
)) {
1209 Status
= EFI_OUT_OF_RESOURCES
;
1213 ScsiIoDevice
->DevicePath
= DevicePath
;
1215 Status
= gBS
->InstallMultipleProtocolInterfaces (
1216 &ScsiIoDevice
->Handle
,
1217 &gEfiDevicePathProtocolGuid
,
1218 ScsiIoDevice
->DevicePath
,
1219 &gEfiScsiIoProtocolGuid
,
1220 &ScsiIoDevice
->ScsiIo
,
1223 if (EFI_ERROR (Status
)) {
1226 if (ScsiBusDev
->ExtScsiSupport
) {
1229 &gEfiExtScsiPassThruProtocolGuid
,
1230 (VOID
**)&(ScsiBusDev
->ExtScsiInterface
),
1231 This
->DriverBindingHandle
,
1232 ScsiIoDevice
->Handle
,
1233 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1238 &gEfiScsiPassThruProtocolGuid
,
1239 (VOID
**)&(ScsiBusDev
->ScsiInterface
),
1240 This
->DriverBindingHandle
,
1241 ScsiIoDevice
->Handle
,
1242 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1252 // The memory space for ScsiDevicePath is allocated in
1253 // ScsiPassThru->BuildDevicePath() function; It is no longer used
1254 // after AppendDevicePathNode,so free the memory it occupies.
1256 FreePool (ScsiDevicePath
);
1258 if (DevicePath
!= NULL
) {
1259 FreePool (DevicePath
);
1262 if (ScsiIoDevice
!= NULL
) {
1263 FreePool (ScsiIoDevice
);
1270 Discovery SCSI Device
1272 @param ScsiIoDevice The pointer of SCSI_IO_DEV
1274 @retval TRUE Find SCSI Device and verify it.
1275 @retval FALSE Unable to find SCSI Device.
1279 DiscoverScsiDevice (
1280 IN OUT SCSI_IO_DEV
*ScsiIoDevice
1284 UINT32 InquiryDataLength
;
1285 UINT8 SenseDataLength
;
1286 UINT8 HostAdapterStatus
;
1288 EFI_SCSI_INQUIRY_DATA
*InquiryData
;
1289 EFI_SCSI_SENSE_DATA
*SenseData
;
1292 BOOLEAN ScsiDeviceFound
;
1294 HostAdapterStatus
= 0;
1298 InquiryData
= AllocateAlignedBuffer (ScsiIoDevice
, sizeof (EFI_SCSI_INQUIRY_DATA
));
1299 if (InquiryData
== NULL
) {
1300 ScsiDeviceFound
= FALSE
;
1304 SenseData
= AllocateAlignedBuffer (
1306 sizeof (EFI_SCSI_SENSE_DATA
)
1308 if (SenseData
== NULL
) {
1309 ScsiDeviceFound
= FALSE
;
1314 // Using Inquiry command to scan for the device
1316 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1317 SenseDataLength
= sizeof (EFI_SCSI_SENSE_DATA
);
1318 ZeroMem (InquiryData
, InquiryDataLength
);
1319 ZeroMem (SenseData
, SenseDataLength
);
1322 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1323 Status
= ScsiInquiryCommand (
1324 &ScsiIoDevice
->ScsiIo
,
1330 (VOID
*)InquiryData
,
1334 if (!EFI_ERROR (Status
)) {
1335 if ((HostAdapterStatus
== EFI_SCSI_IO_STATUS_HOST_ADAPTER_OK
) &&
1336 (TargetStatus
== EFI_SCSI_IO_STATUS_TARGET_CHECK_CONDITION
) &&
1337 (SenseData
->Error_Code
== 0x70) &&
1338 (SenseData
->Sense_Key
== EFI_SCSI_SK_ILLEGAL_REQUEST
))
1340 ScsiDeviceFound
= FALSE
;
1347 if ((Status
== EFI_BAD_BUFFER_SIZE
) ||
1348 (Status
== EFI_INVALID_PARAMETER
) ||
1349 (Status
== EFI_UNSUPPORTED
))
1351 ScsiDeviceFound
= FALSE
;
1356 if (Index
== MaxRetry
) {
1357 ScsiDeviceFound
= FALSE
;
1362 // Retrieved inquiry data successfully
1364 if (InquiryData
->Peripheral_Qualifier
!= 0) {
1365 ScsiDeviceFound
= FALSE
;
1369 if ((InquiryData
->Peripheral_Type
>= EFI_SCSI_TYPE_RESERVED_LOW
) &&
1370 (InquiryData
->Peripheral_Type
<= EFI_SCSI_TYPE_RESERVED_HIGH
))
1372 ScsiDeviceFound
= FALSE
;
1377 // valid device type and peripheral qualifier combination.
1379 ScsiIoDevice
->ScsiDeviceType
= InquiryData
->Peripheral_Type
;
1380 ScsiIoDevice
->RemovableDevice
= InquiryData
->Rmb
;
1381 if (InquiryData
->Version
== 0) {
1382 ScsiIoDevice
->ScsiVersion
= 0;
1385 // ANSI-approved version
1387 ScsiIoDevice
->ScsiVersion
= (UINT8
)(InquiryData
->Version
& 0x07);
1390 ScsiDeviceFound
= TRUE
;
1393 FreeAlignedBuffer (SenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
1394 FreeAlignedBuffer (InquiryData
, sizeof (EFI_SCSI_INQUIRY_DATA
));
1396 return ScsiDeviceFound
;
1400 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.
1402 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1403 @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1408 ScsiioToPassThruPacket (
1409 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
1410 OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
1414 // EFI 1.10 doesn't support Bi-Direction Command.
1416 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL
) {
1417 return EFI_UNSUPPORTED
;
1420 ZeroMem (CommandPacket
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1422 CommandPacket
->Timeout
= Packet
->Timeout
;
1423 CommandPacket
->Cdb
= Packet
->Cdb
;
1424 CommandPacket
->CdbLength
= Packet
->CdbLength
;
1425 CommandPacket
->DataDirection
= Packet
->DataDirection
;
1426 CommandPacket
->HostAdapterStatus
= Packet
->HostAdapterStatus
;
1427 CommandPacket
->TargetStatus
= Packet
->TargetStatus
;
1428 CommandPacket
->SenseData
= Packet
->SenseData
;
1429 CommandPacket
->SenseDataLength
= Packet
->SenseDataLength
;
1431 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1432 CommandPacket
->DataBuffer
= Packet
->InDataBuffer
;
1433 CommandPacket
->TransferLength
= Packet
->InTransferLength
;
1434 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1435 CommandPacket
->DataBuffer
= Packet
->OutDataBuffer
;
1436 CommandPacket
->TransferLength
= Packet
->OutTransferLength
;
1443 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.
1445 @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1446 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1451 PassThruToScsiioPacket (
1452 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
1453 OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
1456 Packet
->Timeout
= ScsiPacket
->Timeout
;
1457 Packet
->Cdb
= ScsiPacket
->Cdb
;
1458 Packet
->CdbLength
= ScsiPacket
->CdbLength
;
1459 Packet
->DataDirection
= ScsiPacket
->DataDirection
;
1460 Packet
->HostAdapterStatus
= ScsiPacket
->HostAdapterStatus
;
1461 Packet
->TargetStatus
= ScsiPacket
->TargetStatus
;
1462 Packet
->SenseData
= ScsiPacket
->SenseData
;
1463 Packet
->SenseDataLength
= ScsiPacket
->SenseDataLength
;
1465 if (ScsiPacket
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1466 Packet
->InDataBuffer
= ScsiPacket
->DataBuffer
;
1467 Packet
->InTransferLength
= ScsiPacket
->TransferLength
;
1468 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1469 Packet
->OutDataBuffer
= ScsiPacket
->DataBuffer
;
1470 Packet
->OutTransferLength
= ScsiPacket
->TransferLength
;
1477 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
1480 @param Event The instance of EFI_EVENT.
1481 @param Context The parameter passed in.
1491 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
;
1492 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
;
1493 EFI_EVENT CallerEvent
;
1494 SCSI_EVENT_DATA
*PassData
;
1496 PassData
= (SCSI_EVENT_DATA
*)Context
;
1497 Packet
= (EFI_SCSI_IO_SCSI_REQUEST_PACKET
*)PassData
->Data1
;
1498 ScsiPacket
= (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)mWorkingBuffer
;
1501 // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.
1503 PassThruToScsiioPacket (ScsiPacket
, Packet
);
1506 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1507 // free mWorkingBuffer.
1509 gBS
->FreePool (mWorkingBuffer
);
1512 // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.
1514 CallerEvent
= PassData
->Data2
;
1515 gBS
->CloseEvent (Event
);
1516 gBS
->SignalEvent (CallerEvent
);