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
,
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 The user Entry Point for module ScsiBus. The user code starts with this function.
77 @param ImageHandle The firmware allocated handle for the EFI image.
78 @param SystemTable A pointer to the EFI System Table.
80 @retval EFI_SUCCESS The entry point is executed successfully.
81 @retval other Some error occurs when executing this entry point.
87 IN EFI_HANDLE ImageHandle
,
88 IN EFI_SYSTEM_TABLE
*SystemTable
94 // Install driver model protocol(s).
96 Status
= EfiLibInstallDriverBindingComponentName2 (
99 &gSCSIBusDriverBinding
,
101 &gScsiBusComponentName
,
102 &gScsiBusComponentName2
104 ASSERT_EFI_ERROR (Status
);
111 Test to see if this driver supports ControllerHandle.
113 This service is called by the EFI boot service ConnectController(). In order
114 to make drivers as small as possible, there are a few calling restrictions for
115 this service. ConnectController() must follow these calling restrictions. If
116 any other agent wishes to call Supported() it must also follow these calling
119 @param This Protocol instance pointer.
120 @param ControllerHandle Handle of device to test
121 @param RemainingDevicePath Optional parameter use to pick a specific child
124 @retval EFI_SUCCESS This driver supports this device
125 @retval EFI_ALREADY_STARTED This driver is already running on this device
126 @retval other This driver does not support this device
131 SCSIBusDriverBindingSupported (
132 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
133 IN EFI_HANDLE Controller
,
134 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
138 EFI_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
139 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtPassThru
;
142 SCSI_TARGET_ID ScsiTargetId
;
144 TargetId
= &ScsiTargetId
.ScsiId
.ExtScsi
[0];
145 SetMem (TargetId
, TARGET_MAX_BYTES
, 0xFF);
148 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
149 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
150 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
152 Status
= gBS
->OpenProtocol (
154 &gEfiExtScsiPassThruProtocolGuid
,
155 (VOID
**)&ExtPassThru
,
156 This
->DriverBindingHandle
,
158 EFI_OPEN_PROTOCOL_BY_DRIVER
161 if (Status
== EFI_ALREADY_STARTED
) {
163 } else if (!EFI_ERROR(Status
)) {
165 // Check if RemainingDevicePath is NULL or the End of Device Path Node,
166 // if yes, return EFI_SUCCESS.
168 if ((RemainingDevicePath
== NULL
) || IsDevicePathEnd (RemainingDevicePath
)) {
170 // Close protocol regardless of RemainingDevicePath validation
174 &gEfiExtScsiPassThruProtocolGuid
,
175 This
->DriverBindingHandle
,
181 // If RemainingDevicePath isn't the End of Device Path Node, check its validation
183 Status
= ExtPassThru
->GetTargetLun (ExtPassThru
, RemainingDevicePath
, &TargetId
, &Lun
);
185 // Close protocol regardless of RemainingDevicePath validation
189 &gEfiExtScsiPassThruProtocolGuid
,
190 This
->DriverBindingHandle
,
193 if (!EFI_ERROR(Status
)) {
200 // Come here in 2 condition:
201 // 1. ExtPassThru doesn't exist.
202 // 2. ExtPassThru exists but RemainingDevicePath is invalid.
204 Status
= gBS
->OpenProtocol (
206 &gEfiScsiPassThruProtocolGuid
,
208 This
->DriverBindingHandle
,
210 EFI_OPEN_PROTOCOL_BY_DRIVER
213 if (Status
== EFI_ALREADY_STARTED
) {
217 if (EFI_ERROR (Status
)) {
222 // Test RemainingDevicePath is valid or not.
224 if ((RemainingDevicePath
!= NULL
) && !IsDevicePathEnd (RemainingDevicePath
)) {
225 Status
= PassThru
->GetTargetLun (PassThru
, RemainingDevicePath
, &ScsiTargetId
.ScsiId
.Scsi
, &Lun
);
230 &gEfiScsiPassThruProtocolGuid
,
231 This
->DriverBindingHandle
,
239 Start this driver on ControllerHandle.
241 This service is called by the EFI boot service ConnectController(). In order
242 to make drivers as small as possible, there are a few calling restrictions for
243 this service. ConnectController() must follow these calling restrictions. If
244 any other agent wishes to call Start() it must also follow these calling
247 @param This Protocol instance pointer.
248 @param ControllerHandle Handle of device to bind driver to
249 @param RemainingDevicePath Optional parameter use to pick a specific child
252 @retval EFI_SUCCESS This driver is added to ControllerHandle
253 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
254 @retval other This driver does not support this device
259 SCSIBusDriverBindingStart (
260 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
261 IN EFI_HANDLE Controller
,
262 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
267 BOOLEAN ScanOtherPuns
;
268 BOOLEAN FromFirstTarget
;
269 BOOLEAN ExtScsiSupport
;
271 EFI_STATUS DevicePathStatus
;
272 EFI_STATUS PassThruStatus
;
273 SCSI_BUS_DEVICE
*ScsiBusDev
;
274 SCSI_TARGET_ID ScsiTargetId
;
275 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
276 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiInterface
;
277 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiInterface
;
278 EFI_SCSI_BUS_PROTOCOL
*BusIdentify
;
281 ScanOtherPuns
= TRUE
;
282 FromFirstTarget
= FALSE
;
283 ExtScsiSupport
= FALSE
;
284 PassThruStatus
= EFI_SUCCESS
;
286 TargetId
= &ScsiTargetId
.ScsiId
.ExtScsi
[0];
287 SetMem (TargetId
, TARGET_MAX_BYTES
, 0xFF);
289 DevicePathStatus
= gBS
->OpenProtocol (
291 &gEfiDevicePathProtocolGuid
,
292 (VOID
**) &ParentDevicePath
,
293 This
->DriverBindingHandle
,
295 EFI_OPEN_PROTOCOL_BY_DRIVER
297 if (EFI_ERROR (DevicePathStatus
) && (DevicePathStatus
!= EFI_ALREADY_STARTED
)) {
298 return DevicePathStatus
;
302 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
303 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
304 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
306 Status
= gBS
->OpenProtocol (
308 &gEfiExtScsiPassThruProtocolGuid
,
309 (VOID
**) &ExtScsiInterface
,
310 This
->DriverBindingHandle
,
312 EFI_OPEN_PROTOCOL_BY_DRIVER
315 // Fail to open UEFI ExtendPassThru Protocol, then try to open EFI PassThru Protocol instead.
317 if (EFI_ERROR(Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
318 Status
= gBS
->OpenProtocol (
320 &gEfiScsiPassThruProtocolGuid
,
321 (VOID
**) &ScsiInterface
,
322 This
->DriverBindingHandle
,
324 EFI_OPEN_PROTOCOL_BY_DRIVER
327 // Fail to open EFI PassThru Protocol, Close the DevicePathProtocol if it is opened by this time.
329 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
330 if (!EFI_ERROR(DevicePathStatus
)) {
333 &gEfiDevicePathProtocolGuid
,
334 This
->DriverBindingHandle
,
342 // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol
343 // with BY_DRIVER if it is also present on the handle. The intent is to prevent
344 // another SCSI Bus Driver to work on the same host handle.
346 ExtScsiSupport
= TRUE
;
347 PassThruStatus
= gBS
->OpenProtocol (
349 &gEfiScsiPassThruProtocolGuid
,
350 (VOID
**) &ScsiInterface
,
351 This
->DriverBindingHandle
,
353 EFI_OPEN_PROTOCOL_BY_DRIVER
357 if (Status
!= EFI_ALREADY_STARTED
) {
359 // Go through here means either ExtPassThru or PassThru Protocol is successfully opened
360 // on this handle for this time. Then construct Host controller private data.
363 ScsiBusDev
= AllocateZeroPool(sizeof(SCSI_BUS_DEVICE
));
364 if (ScsiBusDev
== NULL
) {
365 Status
= EFI_OUT_OF_RESOURCES
;
368 ScsiBusDev
->Signature
= SCSI_BUS_DEVICE_SIGNATURE
;
369 ScsiBusDev
->ExtScsiSupport
= ExtScsiSupport
;
370 ScsiBusDev
->DevicePath
= ParentDevicePath
;
371 if (ScsiBusDev
->ExtScsiSupport
) {
372 ScsiBusDev
->ExtScsiInterface
= ExtScsiInterface
;
374 ScsiBusDev
->ScsiInterface
= ScsiInterface
;
378 // Install EFI_SCSI_BUS_PROTOCOL to the controller handle, So ScsiBusDev could be
379 // retrieved on this controller handle. With ScsiBusDev, we can know which PassThru
380 // Protocol is present on the handle, UEFI ExtPassThru Protocol or EFI PassThru Protocol.
382 Status
= gBS
->InstallProtocolInterface (
385 EFI_NATIVE_INTERFACE
,
386 &ScsiBusDev
->BusIdentify
388 if (EFI_ERROR (Status
)) {
393 // Go through here means Start() is re-invoked again, nothing special is required to do except
394 // picking up Host controller private information.
396 Status
= gBS
->OpenProtocol (
399 (VOID
**) &BusIdentify
,
400 This
->DriverBindingHandle
,
402 EFI_OPEN_PROTOCOL_GET_PROTOCOL
405 if (EFI_ERROR (Status
)) {
408 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify
);
412 if (RemainingDevicePath
== NULL
) {
414 // If RemainingDevicePath is NULL,
415 // must enumerate all SCSI devices anyway
417 FromFirstTarget
= TRUE
;
418 } else if (!IsDevicePathEnd (RemainingDevicePath
)) {
420 // If RemainingDevicePath isn't the End of Device Path Node,
421 // only scan the specified device by RemainingDevicePath
423 if (ScsiBusDev
->ExtScsiSupport
) {
424 Status
= ScsiBusDev
->ExtScsiInterface
->GetTargetLun (ScsiBusDev
->ExtScsiInterface
, RemainingDevicePath
, &TargetId
, &Lun
);
426 Status
= ScsiBusDev
->ScsiInterface
->GetTargetLun (ScsiBusDev
->ScsiInterface
, RemainingDevicePath
, &ScsiTargetId
.ScsiId
.Scsi
, &Lun
);
429 if (EFI_ERROR (Status
)) {
434 // If RemainingDevicePath is the End of Device Path Node,
435 // skip enumerate any device and return EFI_SUCESSS
437 ScanOtherPuns
= FALSE
;
440 while(ScanOtherPuns
) {
441 if (FromFirstTarget
) {
443 // Remaining Device Path is NULL, scan all the possible Puns in the
446 if (ScsiBusDev
->ExtScsiSupport
) {
447 Status
= ScsiBusDev
->ExtScsiInterface
->GetNextTargetLun (ScsiBusDev
->ExtScsiInterface
, &TargetId
, &Lun
);
449 Status
= ScsiBusDev
->ScsiInterface
->GetNextDevice (ScsiBusDev
->ScsiInterface
, &ScsiTargetId
.ScsiId
.Scsi
, &Lun
);
451 if (EFI_ERROR (Status
)) {
453 // no legal Pun and Lun found any more
458 ScanOtherPuns
= FALSE
;
461 // Avoid creating handle for the host adapter.
463 if (ScsiBusDev
->ExtScsiSupport
) {
464 if ((ScsiTargetId
.ScsiId
.Scsi
) == ScsiBusDev
->ExtScsiInterface
->Mode
->AdapterId
) {
468 if ((ScsiTargetId
.ScsiId
.Scsi
) == ScsiBusDev
->ScsiInterface
->Mode
->AdapterId
) {
473 // Scan for the scsi device, if it attaches to the scsi bus,
474 // then create handle and install scsi i/o protocol.
476 Status
= ScsiScanCreateDevice (This
, Controller
, &ScsiTargetId
, Lun
, ScsiBusDev
);
482 if (ScsiBusDev
!= NULL
) {
483 FreePool (ScsiBusDev
);
486 if (ExtScsiSupport
) {
489 &gEfiExtScsiPassThruProtocolGuid
,
490 This
->DriverBindingHandle
,
493 if (!EFI_ERROR (PassThruStatus
)) {
496 &gEfiScsiPassThruProtocolGuid
,
497 This
->DriverBindingHandle
,
504 &gEfiScsiPassThruProtocolGuid
,
505 This
->DriverBindingHandle
,
513 Stop this driver on ControllerHandle.
515 This service is called by the EFI boot service DisconnectController().
516 In order to make drivers as small as possible, there are a few calling
517 restrictions for this service. DisconnectController() must follow these
518 calling restrictions. If any other agent wishes to call Stop() it must also
519 follow these calling restrictions.
521 @param This Protocol instance pointer.
522 @param ControllerHandle Handle of device to stop driver on
523 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
524 children is zero stop the entire bus driver.
525 @param ChildHandleBuffer List of Child Handles to Stop.
527 @retval EFI_SUCCESS This driver is removed ControllerHandle
528 @retval other This driver was not removed from this device
533 SCSIBusDriverBindingStop (
534 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
535 IN EFI_HANDLE Controller
,
536 IN UINTN NumberOfChildren
,
537 IN EFI_HANDLE
*ChildHandleBuffer
541 BOOLEAN AllChildrenStopped
;
543 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
544 SCSI_IO_DEV
*ScsiIoDevice
;
546 EFI_SCSI_BUS_PROTOCOL
*Scsidentifier
;
547 SCSI_BUS_DEVICE
*ScsiBusDev
;
549 if (NumberOfChildren
== 0) {
551 // Get the SCSI_BUS_DEVICE
553 Status
= gBS
->OpenProtocol (
556 (VOID
**) &Scsidentifier
,
557 This
->DriverBindingHandle
,
559 EFI_OPEN_PROTOCOL_GET_PROTOCOL
562 if (EFI_ERROR (Status
)) {
563 return EFI_DEVICE_ERROR
;
566 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier
);
569 // Uninstall SCSI Bus Protocol
571 gBS
->UninstallProtocolInterface (
574 &ScsiBusDev
->BusIdentify
578 // Close the bus driver
580 if (ScsiBusDev
->ExtScsiSupport
) {
582 // Close ExtPassThru Protocol from this controller handle
586 &gEfiExtScsiPassThruProtocolGuid
,
587 This
->DriverBindingHandle
,
591 // When Start() succeeds to open ExtPassThru, it always tries to open PassThru BY_DRIVER.
592 // Its intent is to prevent another SCSI Bus Driver from woking on the same host handle.
593 // So Stop() needs to try to close PassThru if present here.
597 &gEfiScsiPassThruProtocolGuid
,
598 This
->DriverBindingHandle
,
604 &gEfiScsiPassThruProtocolGuid
,
605 This
->DriverBindingHandle
,
612 &gEfiDevicePathProtocolGuid
,
613 This
->DriverBindingHandle
,
616 FreePool (ScsiBusDev
);
620 AllChildrenStopped
= TRUE
;
622 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
624 Status
= gBS
->OpenProtocol (
625 ChildHandleBuffer
[Index
],
626 &gEfiScsiIoProtocolGuid
,
628 This
->DriverBindingHandle
,
630 EFI_OPEN_PROTOCOL_GET_PROTOCOL
632 if (EFI_ERROR (Status
)) {
633 AllChildrenStopped
= FALSE
;
637 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (ScsiIo
);
639 // Close the child handle
641 if (ScsiIoDevice
->ExtScsiSupport
) {
642 Status
= gBS
->CloseProtocol (
644 &gEfiExtScsiPassThruProtocolGuid
,
645 This
->DriverBindingHandle
,
646 ChildHandleBuffer
[Index
]
650 Status
= gBS
->CloseProtocol (
652 &gEfiScsiPassThruProtocolGuid
,
653 This
->DriverBindingHandle
,
654 ChildHandleBuffer
[Index
]
658 Status
= gBS
->UninstallMultipleProtocolInterfaces (
659 ChildHandleBuffer
[Index
],
660 &gEfiDevicePathProtocolGuid
,
661 ScsiIoDevice
->DevicePath
,
662 &gEfiScsiIoProtocolGuid
,
663 &ScsiIoDevice
->ScsiIo
,
666 if (EFI_ERROR (Status
)) {
667 AllChildrenStopped
= FALSE
;
668 if (ScsiIoDevice
->ExtScsiSupport
) {
671 &gEfiExtScsiPassThruProtocolGuid
,
673 This
->DriverBindingHandle
,
674 ChildHandleBuffer
[Index
],
675 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
680 &gEfiScsiPassThruProtocolGuid
,
682 This
->DriverBindingHandle
,
683 ChildHandleBuffer
[Index
],
684 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
688 FreePool (ScsiIoDevice
);
692 if (!AllChildrenStopped
) {
693 return EFI_DEVICE_ERROR
;
701 Retrieves the device type information of the SCSI Controller.
703 @param This Protocol instance pointer.
704 @param DeviceType A pointer to the device type information retrieved from
707 @retval EFI_SUCCESS Retrieves the device type information successfully.
708 @retval EFI_INVALID_PARAMETER The DeviceType is NULL.
714 IN EFI_SCSI_IO_PROTOCOL
*This
,
715 OUT UINT8
*DeviceType
718 SCSI_IO_DEV
*ScsiIoDevice
;
720 if (DeviceType
== NULL
) {
721 return EFI_INVALID_PARAMETER
;
724 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
725 *DeviceType
= ScsiIoDevice
->ScsiDeviceType
;
731 Retrieves the device location in the SCSI channel.
733 @param This Protocol instance pointer.
734 @param Target A pointer to the Target ID of a SCSI device
736 @param Lun A pointer to the LUN of the SCSI device on
739 @retval EFI_SUCCESS Retrieves the device location successfully.
740 @retval EFI_INVALID_PARAMETER The Target or Lun is NULL.
745 ScsiGetDeviceLocation (
746 IN EFI_SCSI_IO_PROTOCOL
*This
,
747 IN OUT UINT8
**Target
,
751 SCSI_IO_DEV
*ScsiIoDevice
;
753 if (Target
== NULL
|| Lun
== NULL
) {
754 return EFI_INVALID_PARAMETER
;
757 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
759 CopyMem (*Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
761 *Lun
= ScsiIoDevice
->Lun
;
767 Resets the SCSI Bus that the SCSI Controller is attached to.
769 @param This Protocol instance pointer.
771 @retval EFI_SUCCESS The SCSI bus is reset successfully.
772 @retval EFI_DEVICE_ERROR Errors encountered when resetting the SCSI bus.
773 @retval EFI_UNSUPPORTED The bus reset operation is not supported by the
774 SCSI Host Controller.
775 @retval EFI_TIMEOUT A timeout occurred while attempting to reset
781 IN EFI_SCSI_IO_PROTOCOL
*This
784 SCSI_IO_DEV
*ScsiIoDevice
;
786 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
788 if (ScsiIoDevice
->ExtScsiSupport
){
789 return ScsiIoDevice
->ExtScsiPassThru
->ResetChannel (ScsiIoDevice
->ExtScsiPassThru
);
791 return ScsiIoDevice
->ScsiPassThru
->ResetChannel (ScsiIoDevice
->ScsiPassThru
);
797 Resets the SCSI Controller that the device handle specifies.
799 @param This Protocol instance pointer.
801 @retval EFI_SUCCESS Reset the SCSI controller successfully.
802 @retval EFI_DEVICE_ERROR Errors are encountered when resetting the SCSI Controller.
803 @retval EFI_UNSUPPORTED The SCSI bus does not support a device reset operation.
804 @retval EFI_TIMEOUT A timeout occurred while attempting to reset the
810 IN EFI_SCSI_IO_PROTOCOL
*This
813 SCSI_IO_DEV
*ScsiIoDevice
;
814 UINT8 Target
[TARGET_MAX_BYTES
];
816 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
817 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
820 if (ScsiIoDevice
->ExtScsiSupport
) {
821 return ScsiIoDevice
->ExtScsiPassThru
->ResetTargetLun (
822 ScsiIoDevice
->ExtScsiPassThru
,
827 return ScsiIoDevice
->ScsiPassThru
->ResetTarget (
828 ScsiIoDevice
->ScsiPassThru
,
829 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
837 Sends a SCSI Request Packet to the SCSI Controller for execution.
839 @param This Protocol instance pointer.
840 @param CommandPacket The SCSI request packet to send to the SCSI
841 Controller specified by the device handle.
842 @param Event If the SCSI bus where the SCSI device is attached
843 does not support non-blocking I/O, then Event is
844 ignored, and blocking I/O is performed.
845 If Event is NULL, then blocking I/O is performed.
846 If Event is not NULL and non-blocking I/O is
847 supported, then non-blocking I/O is performed,
848 and Event will be signaled when the SCSI Request
851 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host
852 successfully, and TransferLength bytes were
853 transferred to/from DataBuffer.See
854 HostAdapterStatus, TargetStatus,
855 SenseDataLength, and SenseData in that order
856 for additional status information.
857 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
858 but the entire DataBuffer could not be transferred.
859 The actual number of bytes transferred is returned
860 in TransferLength. See HostAdapterStatus,
861 TargetStatus, SenseDataLength, and SenseData in
862 that order for additional status information.
863 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
864 there are too many SCSI Command Packets already
865 queued.The caller may retry again later.
866 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
867 the SCSI Request Packet. See HostAdapterStatus,
868 TargetStatus, SenseDataLength, and SenseData in
869 that order for additional status information.
870 @retval EFI_INVALID_PARAMETER The contents of CommandPacket are invalid.
871 The SCSI Request Packet was not sent, so no
872 additional status information is available.
873 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
874 is not supported by the SCSI initiator(i.e., SCSI
875 Host Controller). The SCSI Request Packet was not
876 sent, so no additional status information is
878 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
879 Request Packet to execute. See HostAdapterStatus,
880 TargetStatus, SenseDataLength, and SenseData in
881 that order for additional status information.
885 ScsiExecuteSCSICommand (
886 IN EFI_SCSI_IO_PROTOCOL
*This
,
887 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
888 IN EFI_EVENT Event OPTIONAL
891 SCSI_IO_DEV
*ScsiIoDevice
;
893 UINT8 Target
[TARGET_MAX_BYTES
];
894 EFI_EVENT PacketEvent
;
895 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ExtRequestPacket
;
896 SCSI_EVENT_DATA EventData
;
900 if (Packet
== NULL
) {
901 return EFI_INVALID_PARAMETER
;
904 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
905 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
907 if (ScsiIoDevice
->ExtScsiSupport
) {
908 ExtRequestPacket
= (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*) Packet
;
909 Status
= ScsiIoDevice
->ExtScsiPassThru
->PassThru (
910 ScsiIoDevice
->ExtScsiPassThru
,
918 mWorkingBuffer
= AllocatePool (sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
920 if (mWorkingBuffer
== NULL
) {
921 return EFI_DEVICE_ERROR
;
925 // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.
927 Status
= ScsiioToPassThruPacket(Packet
, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)mWorkingBuffer
);
928 if (EFI_ERROR(Status
)) {
929 FreePool(mWorkingBuffer
);
933 if (((ScsiIoDevice
->ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO
) != 0) && (Event
!= NULL
)) {
934 EventData
.Data1
= (VOID
*)Packet
;
935 EventData
.Data2
= Event
;
939 Status
= gBS
->CreateEvent (
946 if (EFI_ERROR(Status
)) {
947 FreePool(mWorkingBuffer
);
951 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
952 ScsiIoDevice
->ScsiPassThru
,
953 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
959 if (EFI_ERROR(Status
)) {
960 FreePool(mWorkingBuffer
);
961 gBS
->CloseEvent(PacketEvent
);
967 // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert
968 // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.
970 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
971 ScsiIoDevice
->ScsiPassThru
,
972 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
977 if (EFI_ERROR(Status
)) {
978 FreePool(mWorkingBuffer
);
982 PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)mWorkingBuffer
,Packet
);
984 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
985 // free mWorkingBuffer.
987 FreePool(mWorkingBuffer
);
995 Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.
997 @param This Protocol instance pointer
998 @param Controller Controller handle
999 @param TargetId Tartget to be scanned
1000 @param Lun The Lun of the SCSI device on the SCSI channel.
1001 @param ScsiBusDev The pointer of SCSI_BUS_DEVICE
1003 @retval EFI_SUCCESS Successfully to discover the device and attach
1004 ScsiIoProtocol to it.
1005 @retval EFI_OUT_OF_RESOURCES Fail to discover the device.
1010 ScsiScanCreateDevice (
1011 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1012 IN EFI_HANDLE Controller
,
1013 IN SCSI_TARGET_ID
*TargetId
,
1015 IN OUT SCSI_BUS_DEVICE
*ScsiBusDev
1019 SCSI_IO_DEV
*ScsiIoDevice
;
1020 EFI_DEVICE_PATH_PROTOCOL
*ScsiDevicePath
;
1021 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1022 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
1023 EFI_HANDLE DeviceHandle
;
1026 RemainingDevicePath
= NULL
;
1027 ScsiDevicePath
= NULL
;
1028 ScsiIoDevice
= NULL
;
1031 // Build Device Path
1033 if (ScsiBusDev
->ExtScsiSupport
){
1034 Status
= ScsiBusDev
->ExtScsiInterface
->BuildDevicePath (
1035 ScsiBusDev
->ExtScsiInterface
,
1036 &TargetId
->ScsiId
.ExtScsi
[0],
1041 Status
= ScsiBusDev
->ScsiInterface
->BuildDevicePath (
1042 ScsiBusDev
->ScsiInterface
,
1043 TargetId
->ScsiId
.Scsi
,
1049 if (EFI_ERROR(Status
)) {
1053 DevicePath
= AppendDevicePathNode (
1054 ScsiBusDev
->DevicePath
,
1058 if (DevicePath
== NULL
) {
1059 Status
= EFI_OUT_OF_RESOURCES
;
1063 DeviceHandle
= NULL
;
1064 RemainingDevicePath
= DevicePath
;
1065 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &RemainingDevicePath
, &DeviceHandle
);
1066 if (!EFI_ERROR (Status
) && (DeviceHandle
!= NULL
) && IsDevicePathEnd(RemainingDevicePath
)) {
1068 // The device has been started, directly return to fast boot.
1070 Status
= EFI_ALREADY_STARTED
;
1074 ScsiIoDevice
= AllocateZeroPool (sizeof (SCSI_IO_DEV
));
1075 if (ScsiIoDevice
== NULL
) {
1076 Status
= EFI_OUT_OF_RESOURCES
;
1080 ScsiIoDevice
->Signature
= SCSI_IO_DEV_SIGNATURE
;
1081 CopyMem(&ScsiIoDevice
->Pun
, TargetId
, TARGET_MAX_BYTES
);
1082 ScsiIoDevice
->Lun
= Lun
;
1084 if (ScsiBusDev
->ExtScsiSupport
) {
1085 ScsiIoDevice
->ExtScsiPassThru
= ScsiBusDev
->ExtScsiInterface
;
1086 ScsiIoDevice
->ExtScsiSupport
= TRUE
;
1087 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ExtScsiPassThru
->Mode
->IoAlign
;
1090 ScsiIoDevice
->ScsiPassThru
= ScsiBusDev
->ScsiInterface
;
1091 ScsiIoDevice
->ExtScsiSupport
= FALSE
;
1092 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ScsiPassThru
->Mode
->IoAlign
;
1095 ScsiIoDevice
->ScsiIo
.GetDeviceType
= ScsiGetDeviceType
;
1096 ScsiIoDevice
->ScsiIo
.GetDeviceLocation
= ScsiGetDeviceLocation
;
1097 ScsiIoDevice
->ScsiIo
.ResetBus
= ScsiResetBus
;
1098 ScsiIoDevice
->ScsiIo
.ResetDevice
= ScsiResetDevice
;
1099 ScsiIoDevice
->ScsiIo
.ExecuteScsiCommand
= ScsiExecuteSCSICommand
;
1101 if (!DiscoverScsiDevice (ScsiIoDevice
)) {
1102 Status
= EFI_OUT_OF_RESOURCES
;
1106 ScsiIoDevice
->DevicePath
= DevicePath
;
1108 Status
= gBS
->InstallMultipleProtocolInterfaces (
1109 &ScsiIoDevice
->Handle
,
1110 &gEfiDevicePathProtocolGuid
,
1111 ScsiIoDevice
->DevicePath
,
1112 &gEfiScsiIoProtocolGuid
,
1113 &ScsiIoDevice
->ScsiIo
,
1116 if (EFI_ERROR (Status
)) {
1119 if (ScsiBusDev
->ExtScsiSupport
) {
1122 &gEfiExtScsiPassThruProtocolGuid
,
1123 (VOID
**) &(ScsiBusDev
->ExtScsiInterface
),
1124 This
->DriverBindingHandle
,
1125 ScsiIoDevice
->Handle
,
1126 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1131 &gEfiScsiPassThruProtocolGuid
,
1132 (VOID
**) &(ScsiBusDev
->ScsiInterface
),
1133 This
->DriverBindingHandle
,
1134 ScsiIoDevice
->Handle
,
1135 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1144 // The memory space for ScsiDevicePath is allocated in
1145 // ScsiPassThru->BuildDevicePath() function; It is no longer used
1146 // after AppendDevicePathNode,so free the memory it occupies.
1148 FreePool (ScsiDevicePath
);
1150 if (DevicePath
!= NULL
) {
1151 FreePool (DevicePath
);
1154 if (ScsiIoDevice
!= NULL
) {
1155 FreePool (ScsiIoDevice
);
1163 Discovery SCSI Device
1165 @param ScsiIoDevice The pointer of SCSI_IO_DEV
1167 @retval TRUE Find SCSI Device and verify it.
1168 @retval FALSE Unable to find SCSI Device.
1172 DiscoverScsiDevice (
1173 IN OUT SCSI_IO_DEV
*ScsiIoDevice
1177 UINT32 InquiryDataLength
;
1178 UINT8 SenseDataLength
;
1179 UINT8 HostAdapterStatus
;
1181 EFI_SCSI_SENSE_DATA SenseData
;
1182 EFI_SCSI_INQUIRY_DATA InquiryData
;
1186 HostAdapterStatus
= 0;
1189 // Using Inquiry command to scan for the device
1191 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1192 SenseDataLength
= (UINT8
) sizeof (EFI_SCSI_SENSE_DATA
);
1193 ZeroMem (&InquiryData
, InquiryDataLength
);
1196 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1197 Status
= ScsiInquiryCommand (
1198 &ScsiIoDevice
->ScsiIo
,
1199 EFI_TIMER_PERIOD_SECONDS (1),
1200 (VOID
*) &SenseData
,
1204 (VOID
*) &InquiryData
,
1208 if (!EFI_ERROR (Status
)) {
1210 } else if ((Status
== EFI_BAD_BUFFER_SIZE
) ||
1211 (Status
== EFI_INVALID_PARAMETER
) ||
1212 (Status
== EFI_UNSUPPORTED
)) {
1217 if (Index
== MaxRetry
) {
1222 // Retrieved inquiry data successfully
1224 if ((InquiryData
.Peripheral_Qualifier
!= 0) &&
1225 (InquiryData
.Peripheral_Qualifier
!= 3)) {
1229 if (InquiryData
.Peripheral_Qualifier
== 3) {
1230 if (InquiryData
.Peripheral_Type
!= 0x1f) {
1235 if (0x1e >= InquiryData
.Peripheral_Type
&& InquiryData
.Peripheral_Type
>= 0xa) {
1240 // valid device type and peripheral qualifier combination.
1242 ScsiIoDevice
->ScsiDeviceType
= InquiryData
.Peripheral_Type
;
1243 ScsiIoDevice
->RemovableDevice
= InquiryData
.Rmb
;
1244 if (InquiryData
.Version
== 0) {
1245 ScsiIoDevice
->ScsiVersion
= 0;
1248 // ANSI-approved version
1250 ScsiIoDevice
->ScsiVersion
= (UINT8
) (InquiryData
.Version
& 0x07);
1258 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.
1260 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1261 @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1266 ScsiioToPassThruPacket (
1267 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
1268 OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
1272 //EFI 1.10 doesn't support Bi-Direction Command.
1274 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL
) {
1275 return EFI_UNSUPPORTED
;
1278 ZeroMem (CommandPacket
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1280 CommandPacket
->Timeout
= Packet
->Timeout
;
1281 CommandPacket
->Cdb
= Packet
->Cdb
;
1282 CommandPacket
->CdbLength
= Packet
->CdbLength
;
1283 CommandPacket
->DataDirection
= Packet
->DataDirection
;
1284 CommandPacket
->HostAdapterStatus
= Packet
->HostAdapterStatus
;
1285 CommandPacket
->TargetStatus
= Packet
->TargetStatus
;
1286 CommandPacket
->SenseData
= Packet
->SenseData
;
1287 CommandPacket
->SenseDataLength
= Packet
->SenseDataLength
;
1289 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1290 CommandPacket
->DataBuffer
= Packet
->InDataBuffer
;
1291 CommandPacket
->TransferLength
= Packet
->InTransferLength
;
1292 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1293 CommandPacket
->DataBuffer
= Packet
->OutDataBuffer
;
1294 CommandPacket
->TransferLength
= Packet
->OutTransferLength
;
1301 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.
1303 @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1304 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1309 PassThruToScsiioPacket (
1310 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
1311 OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
1314 Packet
->Timeout
= ScsiPacket
->Timeout
;
1315 Packet
->Cdb
= ScsiPacket
->Cdb
;
1316 Packet
->CdbLength
= ScsiPacket
->CdbLength
;
1317 Packet
->DataDirection
= ScsiPacket
->DataDirection
;
1318 Packet
->HostAdapterStatus
= ScsiPacket
->HostAdapterStatus
;
1319 Packet
->TargetStatus
= ScsiPacket
->TargetStatus
;
1320 Packet
->SenseData
= ScsiPacket
->SenseData
;
1321 Packet
->SenseDataLength
= ScsiPacket
->SenseDataLength
;
1323 if (ScsiPacket
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1324 Packet
->InDataBuffer
= ScsiPacket
->DataBuffer
;
1325 Packet
->InTransferLength
= ScsiPacket
->TransferLength
;
1326 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1327 Packet
->OutDataBuffer
= ScsiPacket
->DataBuffer
;
1328 Packet
->OutTransferLength
= ScsiPacket
->TransferLength
;
1335 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
1338 @param Event The instance of EFI_EVENT.
1339 @param Context The parameter passed in.
1349 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
;
1350 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
;
1351 EFI_EVENT CallerEvent
;
1352 SCSI_EVENT_DATA
*PassData
;
1354 PassData
= (SCSI_EVENT_DATA
*)Context
;
1355 Packet
= (EFI_SCSI_IO_SCSI_REQUEST_PACKET
*)PassData
->Data1
;
1356 ScsiPacket
= (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)mWorkingBuffer
;
1359 // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.
1361 PassThruToScsiioPacket(ScsiPacket
, Packet
);
1364 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1365 // free mWorkingBuffer.
1367 gBS
->FreePool(mWorkingBuffer
);
1370 // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.
1372 CallerEvent
= PassData
->Data2
;
1373 gBS
->CloseEvent(Event
);
1374 gBS
->SignalEvent(CallerEvent
);