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 - 2010, 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
,
31 // The ScsiBusProtocol is just used to locate ScsiBusDev
32 // structure in the SCSIBusDriverBindingStop(). Then we can
33 // Close all opened protocols and release this structure.
35 EFI_GUID mScsiBusProtocolGuid
= EFI_SCSI_BUS_PROTOCOL_GUID
;
40 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.
42 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
43 @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
48 ScsiioToPassThruPacket (
49 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
50 OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
54 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.
56 @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
57 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
62 PassThruToScsiioPacket (
63 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
64 OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
68 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
71 @param Event The instance of EFI_EVENT.
72 @param Context The parameter passed in.
83 The user Entry Point for module ScsiBus. The user code starts with this function.
85 @param ImageHandle The firmware allocated handle for the EFI image.
86 @param SystemTable A pointer to the EFI System Table.
88 @retval EFI_SUCCESS The entry point is executed successfully.
89 @retval other Some error occurs when executing this entry point.
95 IN EFI_HANDLE ImageHandle
,
96 IN EFI_SYSTEM_TABLE
*SystemTable
102 // Install driver model protocol(s).
104 Status
= EfiLibInstallDriverBindingComponentName2 (
107 &gSCSIBusDriverBinding
,
109 &gScsiBusComponentName
,
110 &gScsiBusComponentName2
112 ASSERT_EFI_ERROR (Status
);
119 Test to see if this driver supports ControllerHandle.
121 This service is called by the EFI boot service ConnectController(). In order
122 to make drivers as small as possible, there are a few calling restrictions for
123 this service. ConnectController() must follow these calling restrictions. If
124 any other agent wishes to call Supported() it must also follow these calling
127 @param This Protocol instance pointer.
128 @param ControllerHandle Handle of device to test
129 @param RemainingDevicePath Optional parameter use to pick a specific child
132 @retval EFI_SUCCESS This driver supports this device
133 @retval EFI_ALREADY_STARTED This driver is already running on this device
134 @retval other This driver does not support this device
139 SCSIBusDriverBindingSupported (
140 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
141 IN EFI_HANDLE Controller
,
142 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
146 EFI_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
147 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtPassThru
;
150 SCSI_TARGET_ID ScsiTargetId
;
152 TargetId
= &ScsiTargetId
.ScsiId
.ExtScsi
[0];
153 SetMem (TargetId
, TARGET_MAX_BYTES
, 0xFF);
156 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
157 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
158 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
160 Status
= gBS
->OpenProtocol (
162 &gEfiExtScsiPassThruProtocolGuid
,
163 (VOID
**)&ExtPassThru
,
164 This
->DriverBindingHandle
,
166 EFI_OPEN_PROTOCOL_BY_DRIVER
169 if (Status
== EFI_ALREADY_STARTED
) {
171 } else if (!EFI_ERROR(Status
)) {
173 // Check if RemainingDevicePath is NULL or the End of Device Path Node,
174 // if yes, return EFI_SUCCESS.
176 if ((RemainingDevicePath
== NULL
) || IsDevicePathEnd (RemainingDevicePath
)) {
178 // Close protocol regardless of RemainingDevicePath validation
182 &gEfiExtScsiPassThruProtocolGuid
,
183 This
->DriverBindingHandle
,
189 // If RemainingDevicePath isn't the End of Device Path Node, check its validation
191 Status
= ExtPassThru
->GetTargetLun (ExtPassThru
, RemainingDevicePath
, &TargetId
, &Lun
);
193 // Close protocol regardless of RemainingDevicePath validation
197 &gEfiExtScsiPassThruProtocolGuid
,
198 This
->DriverBindingHandle
,
201 if (!EFI_ERROR(Status
)) {
208 // Come here in 2 condition:
209 // 1. ExtPassThru doesn't exist.
210 // 2. ExtPassThru exists but RemainingDevicePath is invalid.
212 Status
= gBS
->OpenProtocol (
214 &gEfiScsiPassThruProtocolGuid
,
216 This
->DriverBindingHandle
,
218 EFI_OPEN_PROTOCOL_BY_DRIVER
221 if (Status
== EFI_ALREADY_STARTED
) {
225 if (EFI_ERROR (Status
)) {
230 // Test RemainingDevicePath is valid or not.
232 if ((RemainingDevicePath
!= NULL
) && !IsDevicePathEnd (RemainingDevicePath
)) {
233 Status
= PassThru
->GetTargetLun (PassThru
, RemainingDevicePath
, &ScsiTargetId
.ScsiId
.Scsi
, &Lun
);
238 &gEfiScsiPassThruProtocolGuid
,
239 This
->DriverBindingHandle
,
247 Start this driver on ControllerHandle.
249 This service is called by the EFI boot service ConnectController(). In order
250 to make drivers as small as possible, there are a few calling restrictions for
251 this service. ConnectController() must follow these calling restrictions. If
252 any other agent wishes to call Start() it must also follow these calling
255 @param This Protocol instance pointer.
256 @param ControllerHandle Handle of device to bind driver to
257 @param RemainingDevicePath Optional parameter use to pick a specific child
260 @retval EFI_SUCCESS This driver is added to ControllerHandle
261 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
262 @retval other This driver does not support this device
267 SCSIBusDriverBindingStart (
268 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
269 IN EFI_HANDLE Controller
,
270 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
275 BOOLEAN ScanOtherPuns
;
276 BOOLEAN FromFirstTarget
;
277 BOOLEAN ExtScsiSupport
;
279 EFI_STATUS DevicePathStatus
;
280 EFI_STATUS PassThruStatus
;
281 SCSI_BUS_DEVICE
*ScsiBusDev
;
282 SCSI_TARGET_ID ScsiTargetId
;
283 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
284 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiInterface
;
285 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiInterface
;
286 EFI_SCSI_BUS_PROTOCOL
*BusIdentify
;
289 ScanOtherPuns
= TRUE
;
290 FromFirstTarget
= FALSE
;
291 ExtScsiSupport
= FALSE
;
292 PassThruStatus
= EFI_SUCCESS
;
294 TargetId
= &ScsiTargetId
.ScsiId
.ExtScsi
[0];
295 SetMem (TargetId
, TARGET_MAX_BYTES
, 0xFF);
297 DevicePathStatus
= gBS
->OpenProtocol (
299 &gEfiDevicePathProtocolGuid
,
300 (VOID
**) &ParentDevicePath
,
301 This
->DriverBindingHandle
,
303 EFI_OPEN_PROTOCOL_BY_DRIVER
305 if (EFI_ERROR (DevicePathStatus
) && (DevicePathStatus
!= EFI_ALREADY_STARTED
)) {
306 return DevicePathStatus
;
310 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
311 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
312 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
314 Status
= gBS
->OpenProtocol (
316 &gEfiExtScsiPassThruProtocolGuid
,
317 (VOID
**) &ExtScsiInterface
,
318 This
->DriverBindingHandle
,
320 EFI_OPEN_PROTOCOL_BY_DRIVER
323 // Fail to open UEFI ExtendPassThru Protocol, then try to open EFI PassThru Protocol instead.
325 if (EFI_ERROR(Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
326 Status
= gBS
->OpenProtocol (
328 &gEfiScsiPassThruProtocolGuid
,
329 (VOID
**) &ScsiInterface
,
330 This
->DriverBindingHandle
,
332 EFI_OPEN_PROTOCOL_BY_DRIVER
335 // Fail to open EFI PassThru Protocol, Close the DevicePathProtocol if it is opened by this time.
337 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
338 if (!EFI_ERROR(DevicePathStatus
)) {
341 &gEfiDevicePathProtocolGuid
,
342 This
->DriverBindingHandle
,
350 // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol
351 // with BY_DRIVER if it is also present on the handle. The intent is to prevent
352 // another SCSI Bus Driver to work on the same host handle.
354 ExtScsiSupport
= TRUE
;
355 PassThruStatus
= gBS
->OpenProtocol (
357 &gEfiScsiPassThruProtocolGuid
,
358 (VOID
**) &ScsiInterface
,
359 This
->DriverBindingHandle
,
361 EFI_OPEN_PROTOCOL_BY_DRIVER
365 if (Status
!= EFI_ALREADY_STARTED
) {
367 // Go through here means either ExtPassThru or PassThru Protocol is successfully opened
368 // on this handle for this time. Then construct Host controller private data.
371 ScsiBusDev
= AllocateZeroPool(sizeof(SCSI_BUS_DEVICE
));
372 if (ScsiBusDev
== NULL
) {
373 Status
= EFI_OUT_OF_RESOURCES
;
376 ScsiBusDev
->Signature
= SCSI_BUS_DEVICE_SIGNATURE
;
377 ScsiBusDev
->ExtScsiSupport
= ExtScsiSupport
;
378 ScsiBusDev
->DevicePath
= ParentDevicePath
;
379 if (ScsiBusDev
->ExtScsiSupport
) {
380 ScsiBusDev
->ExtScsiInterface
= ExtScsiInterface
;
382 ScsiBusDev
->ScsiInterface
= ScsiInterface
;
386 // Install EFI_SCSI_BUS_PROTOCOL to the controller handle, So ScsiBusDev could be
387 // retrieved on this controller handle. With ScsiBusDev, we can know which PassThru
388 // Protocol is present on the handle, UEFI ExtPassThru Protocol or EFI PassThru Protocol.
390 Status
= gBS
->InstallProtocolInterface (
392 &mScsiBusProtocolGuid
,
393 EFI_NATIVE_INTERFACE
,
394 &ScsiBusDev
->BusIdentify
396 if (EFI_ERROR (Status
)) {
401 // Go through here means Start() is re-invoked again, nothing special is required to do except
402 // picking up Host controller private information.
404 Status
= gBS
->OpenProtocol (
406 &mScsiBusProtocolGuid
,
407 (VOID
**) &BusIdentify
,
408 This
->DriverBindingHandle
,
410 EFI_OPEN_PROTOCOL_GET_PROTOCOL
413 if (EFI_ERROR (Status
)) {
416 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify
);
420 if (RemainingDevicePath
== NULL
) {
422 // If RemainingDevicePath is NULL,
423 // must enumerate all SCSI devices anyway
425 FromFirstTarget
= TRUE
;
426 } else if (!IsDevicePathEnd (RemainingDevicePath
)) {
428 // If RemainingDevicePath isn't the End of Device Path Node,
429 // only scan the specified device by RemainingDevicePath
431 if (ScsiBusDev
->ExtScsiSupport
) {
432 Status
= ScsiBusDev
->ExtScsiInterface
->GetTargetLun (ScsiBusDev
->ExtScsiInterface
, RemainingDevicePath
, &TargetId
, &Lun
);
434 Status
= ScsiBusDev
->ScsiInterface
->GetTargetLun (ScsiBusDev
->ScsiInterface
, RemainingDevicePath
, &ScsiTargetId
.ScsiId
.Scsi
, &Lun
);
437 if (EFI_ERROR (Status
)) {
442 // If RemainingDevicePath is the End of Device Path Node,
443 // skip enumerate any device and return EFI_SUCESSS
445 ScanOtherPuns
= FALSE
;
448 while(ScanOtherPuns
) {
449 if (FromFirstTarget
) {
451 // Remaining Device Path is NULL, scan all the possible Puns in the
454 if (ScsiBusDev
->ExtScsiSupport
) {
455 Status
= ScsiBusDev
->ExtScsiInterface
->GetNextTargetLun (ScsiBusDev
->ExtScsiInterface
, &TargetId
, &Lun
);
457 Status
= ScsiBusDev
->ScsiInterface
->GetNextDevice (ScsiBusDev
->ScsiInterface
, &ScsiTargetId
.ScsiId
.Scsi
, &Lun
);
459 if (EFI_ERROR (Status
)) {
461 // no legal Pun and Lun found any more
466 ScanOtherPuns
= FALSE
;
469 // Avoid creating handle for the host adapter.
471 if (ScsiBusDev
->ExtScsiSupport
) {
472 if ((ScsiTargetId
.ScsiId
.Scsi
) == ScsiBusDev
->ExtScsiInterface
->Mode
->AdapterId
) {
476 if ((ScsiTargetId
.ScsiId
.Scsi
) == ScsiBusDev
->ScsiInterface
->Mode
->AdapterId
) {
481 // Scan for the scsi device, if it attaches to the scsi bus,
482 // then create handle and install scsi i/o protocol.
484 Status
= ScsiScanCreateDevice (This
, Controller
, &ScsiTargetId
, Lun
, ScsiBusDev
);
490 if (ScsiBusDev
!= NULL
) {
491 FreePool (ScsiBusDev
);
494 if (ExtScsiSupport
) {
497 &gEfiExtScsiPassThruProtocolGuid
,
498 This
->DriverBindingHandle
,
501 if (!EFI_ERROR (PassThruStatus
)) {
504 &gEfiScsiPassThruProtocolGuid
,
505 This
->DriverBindingHandle
,
512 &gEfiScsiPassThruProtocolGuid
,
513 This
->DriverBindingHandle
,
521 Stop this driver on ControllerHandle.
523 This service is called by the EFI boot service DisconnectController().
524 In order to make drivers as small as possible, there are a few calling
525 restrictions for this service. DisconnectController() must follow these
526 calling restrictions. If any other agent wishes to call Stop() it must also
527 follow these calling restrictions.
529 @param This Protocol instance pointer.
530 @param ControllerHandle Handle of device to stop driver on
531 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
532 children is zero stop the entire bus driver.
533 @param ChildHandleBuffer List of Child Handles to Stop.
535 @retval EFI_SUCCESS This driver is removed ControllerHandle
536 @retval other This driver was not removed from this device
541 SCSIBusDriverBindingStop (
542 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
543 IN EFI_HANDLE Controller
,
544 IN UINTN NumberOfChildren
,
545 IN EFI_HANDLE
*ChildHandleBuffer
549 BOOLEAN AllChildrenStopped
;
551 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
552 SCSI_IO_DEV
*ScsiIoDevice
;
554 EFI_SCSI_BUS_PROTOCOL
*Scsidentifier
;
555 SCSI_BUS_DEVICE
*ScsiBusDev
;
557 if (NumberOfChildren
== 0) {
559 // Get the SCSI_BUS_DEVICE
561 Status
= gBS
->OpenProtocol (
563 &mScsiBusProtocolGuid
,
564 (VOID
**) &Scsidentifier
,
565 This
->DriverBindingHandle
,
567 EFI_OPEN_PROTOCOL_GET_PROTOCOL
570 if (EFI_ERROR (Status
)) {
571 return EFI_DEVICE_ERROR
;
574 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier
);
577 // Uninstall SCSI Bus Protocol
579 gBS
->UninstallProtocolInterface (
581 &mScsiBusProtocolGuid
,
582 &ScsiBusDev
->BusIdentify
586 // Close the bus driver
588 if (ScsiBusDev
->ExtScsiSupport
) {
590 // Close ExtPassThru Protocol from this controller handle
594 &gEfiExtScsiPassThruProtocolGuid
,
595 This
->DriverBindingHandle
,
599 // When Start() succeeds to open ExtPassThru, it always tries to open PassThru BY_DRIVER.
600 // Its intent is to prevent another SCSI Bus Driver from woking on the same host handle.
601 // So Stop() needs to try to close PassThru if present here.
605 &gEfiScsiPassThruProtocolGuid
,
606 This
->DriverBindingHandle
,
612 &gEfiScsiPassThruProtocolGuid
,
613 This
->DriverBindingHandle
,
620 &gEfiDevicePathProtocolGuid
,
621 This
->DriverBindingHandle
,
624 FreePool (ScsiBusDev
);
628 AllChildrenStopped
= TRUE
;
630 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
632 Status
= gBS
->OpenProtocol (
633 ChildHandleBuffer
[Index
],
634 &gEfiScsiIoProtocolGuid
,
636 This
->DriverBindingHandle
,
638 EFI_OPEN_PROTOCOL_GET_PROTOCOL
640 if (EFI_ERROR (Status
)) {
641 AllChildrenStopped
= FALSE
;
645 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (ScsiIo
);
647 // Close the child handle
649 if (ScsiIoDevice
->ExtScsiSupport
) {
650 Status
= gBS
->CloseProtocol (
652 &gEfiExtScsiPassThruProtocolGuid
,
653 This
->DriverBindingHandle
,
654 ChildHandleBuffer
[Index
]
658 Status
= gBS
->CloseProtocol (
660 &gEfiScsiPassThruProtocolGuid
,
661 This
->DriverBindingHandle
,
662 ChildHandleBuffer
[Index
]
666 Status
= gBS
->UninstallMultipleProtocolInterfaces (
667 ChildHandleBuffer
[Index
],
668 &gEfiDevicePathProtocolGuid
,
669 ScsiIoDevice
->DevicePath
,
670 &gEfiScsiIoProtocolGuid
,
671 &ScsiIoDevice
->ScsiIo
,
674 if (EFI_ERROR (Status
)) {
675 AllChildrenStopped
= FALSE
;
676 if (ScsiIoDevice
->ExtScsiSupport
) {
679 &gEfiExtScsiPassThruProtocolGuid
,
681 This
->DriverBindingHandle
,
682 ChildHandleBuffer
[Index
],
683 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
688 &gEfiScsiPassThruProtocolGuid
,
690 This
->DriverBindingHandle
,
691 ChildHandleBuffer
[Index
],
692 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
696 FreePool (ScsiIoDevice
);
700 if (!AllChildrenStopped
) {
701 return EFI_DEVICE_ERROR
;
709 Retrieves the device type information of the SCSI Controller.
711 @param This Protocol instance pointer.
712 @param DeviceType A pointer to the device type information retrieved from
715 @retval EFI_SUCCESS Retrieves the device type information successfully.
716 @retval EFI_INVALID_PARAMETER The DeviceType is NULL.
722 IN EFI_SCSI_IO_PROTOCOL
*This
,
723 OUT UINT8
*DeviceType
726 SCSI_IO_DEV
*ScsiIoDevice
;
728 if (DeviceType
== NULL
) {
729 return EFI_INVALID_PARAMETER
;
732 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
733 *DeviceType
= ScsiIoDevice
->ScsiDeviceType
;
739 Retrieves the device location in the SCSI channel.
741 @param This Protocol instance pointer.
742 @param Target A pointer to the Target ID of a SCSI device
744 @param Lun A pointer to the LUN of the SCSI device on
747 @retval EFI_SUCCESS Retrieves the device location successfully.
748 @retval EFI_INVALID_PARAMETER The Target or Lun is NULL.
753 ScsiGetDeviceLocation (
754 IN EFI_SCSI_IO_PROTOCOL
*This
,
755 IN OUT UINT8
**Target
,
759 SCSI_IO_DEV
*ScsiIoDevice
;
761 if (Target
== NULL
|| Lun
== NULL
) {
762 return EFI_INVALID_PARAMETER
;
765 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
767 CopyMem (*Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
769 *Lun
= ScsiIoDevice
->Lun
;
775 Resets the SCSI Bus that the SCSI Controller is attached to.
777 @param This Protocol instance pointer.
779 @retval EFI_SUCCESS The SCSI bus is reset successfully.
780 @retval EFI_DEVICE_ERROR Errors encountered when resetting the SCSI bus.
781 @retval EFI_UNSUPPORTED The bus reset operation is not supported by the
782 SCSI Host Controller.
783 @retval EFI_TIMEOUT A timeout occurred while attempting to reset
789 IN EFI_SCSI_IO_PROTOCOL
*This
792 SCSI_IO_DEV
*ScsiIoDevice
;
794 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
796 if (ScsiIoDevice
->ExtScsiSupport
){
797 return ScsiIoDevice
->ExtScsiPassThru
->ResetChannel (ScsiIoDevice
->ExtScsiPassThru
);
799 return ScsiIoDevice
->ScsiPassThru
->ResetChannel (ScsiIoDevice
->ScsiPassThru
);
805 Resets the SCSI Controller that the device handle specifies.
807 @param This Protocol instance pointer.
809 @retval EFI_SUCCESS Reset the SCSI controller successfully.
810 @retval EFI_DEVICE_ERROR Errors are encountered when resetting the SCSI Controller.
811 @retval EFI_UNSUPPORTED The SCSI bus does not support a device reset operation.
812 @retval EFI_TIMEOUT A timeout occurred while attempting to reset the
818 IN EFI_SCSI_IO_PROTOCOL
*This
821 SCSI_IO_DEV
*ScsiIoDevice
;
822 UINT8 Target
[TARGET_MAX_BYTES
];
824 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
825 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
828 if (ScsiIoDevice
->ExtScsiSupport
) {
829 return ScsiIoDevice
->ExtScsiPassThru
->ResetTargetLun (
830 ScsiIoDevice
->ExtScsiPassThru
,
835 return ScsiIoDevice
->ScsiPassThru
->ResetTarget (
836 ScsiIoDevice
->ScsiPassThru
,
837 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
845 Sends a SCSI Request Packet to the SCSI Controller for execution.
847 @param This Protocol instance pointer.
848 @param CommandPacket The SCSI request packet to send to the SCSI
849 Controller specified by the device handle.
850 @param Event If the SCSI bus where the SCSI device is attached
851 does not support non-blocking I/O, then Event is
852 ignored, and blocking I/O is performed.
853 If Event is NULL, then blocking I/O is performed.
854 If Event is not NULL and non-blocking I/O is
855 supported, then non-blocking I/O is performed,
856 and Event will be signaled when the SCSI Request
859 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host
860 successfully, and TransferLength bytes were
861 transferred to/from DataBuffer.See
862 HostAdapterStatus, TargetStatus,
863 SenseDataLength, and SenseData in that order
864 for additional status information.
865 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
866 but the entire DataBuffer could not be transferred.
867 The actual number of bytes transferred is returned
868 in TransferLength. See HostAdapterStatus,
869 TargetStatus, SenseDataLength, and SenseData in
870 that order for additional status information.
871 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
872 there are too many SCSI Command Packets already
873 queued.The caller may retry again later.
874 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
875 the SCSI Request Packet. See HostAdapterStatus,
876 TargetStatus, SenseDataLength, and SenseData in
877 that order for additional status information.
878 @retval EFI_INVALID_PARAMETER The contents of CommandPacket are invalid.
879 The SCSI Request Packet was not sent, so no
880 additional status information is available.
881 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
882 is not supported by the SCSI initiator(i.e., SCSI
883 Host Controller). The SCSI Request Packet was not
884 sent, so no additional status information is
886 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
887 Request Packet to execute. See HostAdapterStatus,
888 TargetStatus, SenseDataLength, and SenseData in
889 that order for additional status information.
893 ScsiExecuteSCSICommand (
894 IN EFI_SCSI_IO_PROTOCOL
*This
,
895 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
896 IN EFI_EVENT Event OPTIONAL
899 SCSI_IO_DEV
*ScsiIoDevice
;
901 UINT8 Target
[TARGET_MAX_BYTES
];
902 EFI_EVENT PacketEvent
;
903 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ExtRequestPacket
;
904 SCSI_EVENT_DATA EventData
;
908 if (Packet
== NULL
) {
909 return EFI_INVALID_PARAMETER
;
912 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
913 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
915 if (ScsiIoDevice
->ExtScsiSupport
) {
916 ExtRequestPacket
= (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*) Packet
;
917 Status
= ScsiIoDevice
->ExtScsiPassThru
->PassThru (
918 ScsiIoDevice
->ExtScsiPassThru
,
926 mWorkingBuffer
= AllocatePool (sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
928 if (mWorkingBuffer
== NULL
) {
929 return EFI_DEVICE_ERROR
;
933 // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.
935 Status
= ScsiioToPassThruPacket(Packet
, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)mWorkingBuffer
);
936 if (EFI_ERROR(Status
)) {
937 FreePool(mWorkingBuffer
);
941 if (((ScsiIoDevice
->ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO
) != 0) && (Event
!= NULL
)) {
942 EventData
.Data1
= (VOID
*)Packet
;
943 EventData
.Data2
= Event
;
947 Status
= gBS
->CreateEvent (
954 if (EFI_ERROR(Status
)) {
955 FreePool(mWorkingBuffer
);
959 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
960 ScsiIoDevice
->ScsiPassThru
,
961 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
967 if (EFI_ERROR(Status
)) {
968 FreePool(mWorkingBuffer
);
969 gBS
->CloseEvent(PacketEvent
);
975 // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert
976 // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.
978 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
979 ScsiIoDevice
->ScsiPassThru
,
980 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
985 if (EFI_ERROR(Status
)) {
986 FreePool(mWorkingBuffer
);
990 PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)mWorkingBuffer
,Packet
);
992 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
993 // free mWorkingBuffer.
995 FreePool(mWorkingBuffer
);
1003 Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.
1005 @param This Protocol instance pointer
1006 @param Controller Controller handle
1007 @param TargetId Tartget to be scanned
1008 @param Lun The Lun of the SCSI device on the SCSI channel.
1009 @param ScsiBusDev The pointer of SCSI_BUS_DEVICE
1011 @retval EFI_SUCCESS Successfully to discover the device and attach
1012 ScsiIoProtocol to it.
1013 @retval EFI_OUT_OF_RESOURCES Fail to discover the device.
1018 ScsiScanCreateDevice (
1019 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1020 IN EFI_HANDLE Controller
,
1021 IN SCSI_TARGET_ID
*TargetId
,
1023 IN OUT SCSI_BUS_DEVICE
*ScsiBusDev
1027 SCSI_IO_DEV
*ScsiIoDevice
;
1028 EFI_DEVICE_PATH_PROTOCOL
*ScsiDevicePath
;
1030 ScsiIoDevice
= AllocateZeroPool (sizeof (SCSI_IO_DEV
));
1031 if (ScsiIoDevice
== NULL
) {
1032 return EFI_OUT_OF_RESOURCES
;
1035 ScsiIoDevice
->Signature
= SCSI_IO_DEV_SIGNATURE
;
1036 CopyMem(&ScsiIoDevice
->Pun
, TargetId
, TARGET_MAX_BYTES
);
1037 ScsiIoDevice
->Lun
= Lun
;
1039 if (ScsiBusDev
->ExtScsiSupport
) {
1040 ScsiIoDevice
->ExtScsiPassThru
= ScsiBusDev
->ExtScsiInterface
;
1041 ScsiIoDevice
->ExtScsiSupport
= TRUE
;
1042 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ExtScsiPassThru
->Mode
->IoAlign
;
1045 ScsiIoDevice
->ScsiPassThru
= ScsiBusDev
->ScsiInterface
;
1046 ScsiIoDevice
->ExtScsiSupport
= FALSE
;
1047 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ScsiPassThru
->Mode
->IoAlign
;
1050 ScsiIoDevice
->ScsiIo
.GetDeviceType
= ScsiGetDeviceType
;
1051 ScsiIoDevice
->ScsiIo
.GetDeviceLocation
= ScsiGetDeviceLocation
;
1052 ScsiIoDevice
->ScsiIo
.ResetBus
= ScsiResetBus
;
1053 ScsiIoDevice
->ScsiIo
.ResetDevice
= ScsiResetDevice
;
1054 ScsiIoDevice
->ScsiIo
.ExecuteScsiCommand
= ScsiExecuteSCSICommand
;
1057 if (!DiscoverScsiDevice (ScsiIoDevice
)) {
1058 FreePool (ScsiIoDevice
);
1059 return EFI_OUT_OF_RESOURCES
;
1065 ScsiDevicePath
= NULL
;
1066 if (ScsiIoDevice
->ExtScsiSupport
){
1067 Status
= ScsiIoDevice
->ExtScsiPassThru
->BuildDevicePath (
1068 ScsiIoDevice
->ExtScsiPassThru
,
1069 &ScsiIoDevice
->Pun
.ScsiId
.ExtScsi
[0],
1074 Status
= ScsiIoDevice
->ScsiPassThru
->BuildDevicePath (
1075 ScsiIoDevice
->ScsiPassThru
,
1076 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
1082 if (EFI_ERROR(Status
)) {
1083 FreePool (ScsiIoDevice
);
1087 ScsiIoDevice
->DevicePath
= AppendDevicePathNode (
1088 ScsiBusDev
->DevicePath
,
1092 // The memory space for ScsiDevicePath is allocated in
1093 // ScsiPassThru->BuildDevicePath() function; It is no longer used
1094 // after EfiAppendDevicePathNode,so free the memory it occupies.
1096 FreePool (ScsiDevicePath
);
1098 if (ScsiIoDevice
->DevicePath
== NULL
) {
1099 FreePool (ScsiIoDevice
);
1100 return EFI_OUT_OF_RESOURCES
;
1103 Status
= gBS
->InstallMultipleProtocolInterfaces (
1104 &ScsiIoDevice
->Handle
,
1105 &gEfiDevicePathProtocolGuid
,
1106 ScsiIoDevice
->DevicePath
,
1107 &gEfiScsiIoProtocolGuid
,
1108 &ScsiIoDevice
->ScsiIo
,
1111 if (EFI_ERROR (Status
)) {
1112 FreePool (ScsiIoDevice
->DevicePath
);
1113 FreePool (ScsiIoDevice
);
1114 return EFI_OUT_OF_RESOURCES
;
1116 if (ScsiBusDev
->ExtScsiSupport
) {
1119 &gEfiExtScsiPassThruProtocolGuid
,
1120 (VOID
**) &(ScsiBusDev
->ExtScsiInterface
),
1121 This
->DriverBindingHandle
,
1122 ScsiIoDevice
->Handle
,
1123 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1128 &gEfiScsiPassThruProtocolGuid
,
1129 (VOID
**) &(ScsiBusDev
->ScsiInterface
),
1130 This
->DriverBindingHandle
,
1131 ScsiIoDevice
->Handle
,
1132 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1141 Discovery SCSI Device
1143 @param ScsiIoDevice The pointer of SCSI_IO_DEV
1145 @retval TRUE Find SCSI Device and verify it.
1146 @retval FALSE Unable to find SCSI Device.
1150 DiscoverScsiDevice (
1151 IN OUT SCSI_IO_DEV
*ScsiIoDevice
1155 UINT32 InquiryDataLength
;
1156 UINT8 SenseDataLength
;
1157 UINT8 HostAdapterStatus
;
1159 EFI_SCSI_SENSE_DATA SenseData
;
1160 EFI_SCSI_INQUIRY_DATA InquiryData
;
1162 HostAdapterStatus
= 0;
1165 // Using Inquiry command to scan for the device
1167 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1168 SenseDataLength
= (UINT8
) sizeof (EFI_SCSI_SENSE_DATA
);
1170 Status
= ScsiInquiryCommand (
1171 &ScsiIoDevice
->ScsiIo
,
1172 EFI_TIMER_PERIOD_SECONDS (1),
1173 (VOID
*) &SenseData
,
1177 (VOID
*) &InquiryData
,
1181 if (EFI_ERROR (Status
) && Status
!= EFI_BAD_BUFFER_SIZE
) {
1185 // Retrieved inquiry data successfully
1187 if ((InquiryData
.Peripheral_Qualifier
!= 0) &&
1188 (InquiryData
.Peripheral_Qualifier
!= 3)) {
1192 if (InquiryData
.Peripheral_Qualifier
== 3) {
1193 if (InquiryData
.Peripheral_Type
!= 0x1f) {
1198 if (0x1e >= InquiryData
.Peripheral_Type
&& InquiryData
.Peripheral_Type
>= 0xa) {
1203 // valid device type and peripheral qualifier combination.
1205 ScsiIoDevice
->ScsiDeviceType
= InquiryData
.Peripheral_Type
;
1206 ScsiIoDevice
->RemovableDevice
= InquiryData
.Rmb
;
1207 if (InquiryData
.Version
== 0) {
1208 ScsiIoDevice
->ScsiVersion
= 0;
1211 // ANSI-approved version
1213 ScsiIoDevice
->ScsiVersion
= (UINT8
) (InquiryData
.Version
& 0x07);
1221 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.
1223 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1224 @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1229 ScsiioToPassThruPacket (
1230 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
1231 OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
1235 //EFI 1.10 doesn't support Bi-Direction Command.
1237 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL
) {
1238 return EFI_UNSUPPORTED
;
1241 ZeroMem (CommandPacket
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1243 CommandPacket
->Timeout
= Packet
->Timeout
;
1244 CommandPacket
->Cdb
= Packet
->Cdb
;
1245 CommandPacket
->CdbLength
= Packet
->CdbLength
;
1246 CommandPacket
->DataDirection
= Packet
->DataDirection
;
1247 CommandPacket
->HostAdapterStatus
= Packet
->HostAdapterStatus
;
1248 CommandPacket
->TargetStatus
= Packet
->TargetStatus
;
1249 CommandPacket
->SenseData
= Packet
->SenseData
;
1250 CommandPacket
->SenseDataLength
= Packet
->SenseDataLength
;
1252 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1253 CommandPacket
->DataBuffer
= Packet
->InDataBuffer
;
1254 CommandPacket
->TransferLength
= Packet
->InTransferLength
;
1255 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1256 CommandPacket
->DataBuffer
= Packet
->OutDataBuffer
;
1257 CommandPacket
->TransferLength
= Packet
->OutTransferLength
;
1264 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.
1266 @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1267 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1272 PassThruToScsiioPacket (
1273 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
1274 OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
1277 Packet
->Timeout
= ScsiPacket
->Timeout
;
1278 Packet
->Cdb
= ScsiPacket
->Cdb
;
1279 Packet
->CdbLength
= ScsiPacket
->CdbLength
;
1280 Packet
->DataDirection
= ScsiPacket
->DataDirection
;
1281 Packet
->HostAdapterStatus
= ScsiPacket
->HostAdapterStatus
;
1282 Packet
->TargetStatus
= ScsiPacket
->TargetStatus
;
1283 Packet
->SenseData
= ScsiPacket
->SenseData
;
1284 Packet
->SenseDataLength
= ScsiPacket
->SenseDataLength
;
1286 if (ScsiPacket
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1287 Packet
->InDataBuffer
= ScsiPacket
->DataBuffer
;
1288 Packet
->InTransferLength
= ScsiPacket
->TransferLength
;
1289 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1290 Packet
->OutDataBuffer
= ScsiPacket
->DataBuffer
;
1291 Packet
->OutTransferLength
= ScsiPacket
->TransferLength
;
1298 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
1301 @param Event The instance of EFI_EVENT.
1302 @param Context The parameter passed in.
1312 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
;
1313 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
;
1314 EFI_EVENT CallerEvent
;
1315 SCSI_EVENT_DATA
*PassData
;
1317 PassData
= (SCSI_EVENT_DATA
*)Context
;
1318 Packet
= (EFI_SCSI_IO_SCSI_REQUEST_PACKET
*)PassData
->Data1
;
1319 ScsiPacket
= (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)mWorkingBuffer
;
1322 // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.
1324 PassThruToScsiioPacket(ScsiPacket
, Packet
);
1327 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1328 // free mWorkingBuffer.
1330 gBS
->FreePool(mWorkingBuffer
);
1333 // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.
1335 CallerEvent
= PassData
->Data2
;
1336 gBS
->CloseEvent(Event
);
1337 gBS
->SignalEvent(CallerEvent
);