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 - 2008, Intel Corporation. <BR>
6 All rights reserved. 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
;
149 // Check for the existence of Extended SCSI Pass Thru Protocol and SCSI Pass Thru Protocol
151 Status
= gBS
->OpenProtocol (
153 &gEfiExtScsiPassThruProtocolGuid
,
154 (VOID
**)&ExtPassThru
,
155 This
->DriverBindingHandle
,
157 EFI_OPEN_PROTOCOL_BY_DRIVER
160 if (Status
== EFI_ALREADY_STARTED
) {
164 if (EFI_ERROR (Status
)) {
165 Status
= gBS
->OpenProtocol (
167 &gEfiScsiPassThruProtocolGuid
,
169 This
->DriverBindingHandle
,
171 EFI_OPEN_PROTOCOL_BY_DRIVER
174 if (Status
== EFI_ALREADY_STARTED
) {
178 if (EFI_ERROR (Status
)) {
184 &gEfiScsiPassThruProtocolGuid
,
185 This
->DriverBindingHandle
,
193 &gEfiExtScsiPassThruProtocolGuid
,
194 This
->DriverBindingHandle
,
203 Start this driver on ControllerHandle.
205 This service is called by the EFI boot service ConnectController(). In order
206 to make drivers as small as possible, there are a few calling restrictions for
207 this service. ConnectController() must follow these calling restrictions. If
208 any other agent wishes to call Start() it must also follow these calling
211 @param This Protocol instance pointer.
212 @param ControllerHandle Handle of device to bind driver to
213 @param RemainingDevicePath Optional parameter use to pick a specific child
216 @retval EFI_SUCCESS This driver is added to ControllerHandle
217 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
218 @retval other This driver does not support this device
223 SCSIBusDriverBindingStart (
224 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
225 IN EFI_HANDLE Controller
,
226 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
231 BOOLEAN ScanOtherPuns
;
232 BOOLEAN FromFirstTarget
;
233 BOOLEAN ExtScsiSupport
;
235 EFI_STATUS DevicePathStatus
;
236 EFI_STATUS PassThruStatus
;
237 SCSI_BUS_DEVICE
*ScsiBusDev
;
238 SCSI_TARGET_ID
*ScsiTargetId
;
239 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
240 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiInterface
;
241 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiInterface
;
242 EFI_SCSI_BUS_PROTOCOL
*BusIdentify
;
246 ScanOtherPuns
= TRUE
;
247 FromFirstTarget
= FALSE
;
248 ExtScsiSupport
= FALSE
;
249 PassThruStatus
= EFI_SUCCESS
;
251 ScsiTargetId
= AllocateZeroPool(sizeof(SCSI_TARGET_ID
));
252 if (ScsiTargetId
== NULL
) {
253 return EFI_OUT_OF_RESOURCES
;
256 TargetId
= &ScsiTargetId
->ScsiId
.ExtScsi
[0];
258 DevicePathStatus
= gBS
->OpenProtocol (
260 &gEfiDevicePathProtocolGuid
,
261 (VOID
**) &ParentDevicePath
,
262 This
->DriverBindingHandle
,
264 EFI_OPEN_PROTOCOL_BY_DRIVER
266 if (EFI_ERROR (DevicePathStatus
) && (DevicePathStatus
!= EFI_ALREADY_STARTED
)) {
267 return DevicePathStatus
;
271 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
272 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
273 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
275 Status
= gBS
->OpenProtocol (
277 &gEfiExtScsiPassThruProtocolGuid
,
278 (VOID
**) &ExtScsiInterface
,
279 This
->DriverBindingHandle
,
281 EFI_OPEN_PROTOCOL_BY_DRIVER
284 // Fail to open UEFI ExtendPassThru Protocol, then try to open EFI PassThru Protocol instead.
286 if (EFI_ERROR(Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
287 Status
= gBS
->OpenProtocol (
289 &gEfiScsiPassThruProtocolGuid
,
290 (VOID
**) &ScsiInterface
,
291 This
->DriverBindingHandle
,
293 EFI_OPEN_PROTOCOL_BY_DRIVER
296 // Fail to open EFI PassThru Protocol, Close the DevicePathProtocol if it is opened by this time.
298 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
299 if (!EFI_ERROR(DevicePathStatus
)) {
302 &gEfiDevicePathProtocolGuid
,
303 This
->DriverBindingHandle
,
311 // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol
312 // with BY_DRIVER if it is also present on the handle. The intent is to prevent
313 // another SCSI Bus Driver to work on the same host handle.
315 ExtScsiSupport
= TRUE
;
316 PassThruStatus
= gBS
->OpenProtocol (
318 &gEfiScsiPassThruProtocolGuid
,
319 (VOID
**) &ScsiInterface
,
320 This
->DriverBindingHandle
,
322 EFI_OPEN_PROTOCOL_BY_DRIVER
326 if (Status
!= EFI_ALREADY_STARTED
) {
328 // Go through here means either ExtPassThru or PassThru Protocol is successfully opened
329 // on this handle for this time. Then construct Host controller private data.
332 ScsiBusDev
= AllocateZeroPool(sizeof(SCSI_BUS_DEVICE
));
333 if (ScsiBusDev
== NULL
) {
334 Status
= EFI_OUT_OF_RESOURCES
;
337 ScsiBusDev
->Signature
= SCSI_BUS_DEVICE_SIGNATURE
;
338 ScsiBusDev
->ExtScsiSupport
= ExtScsiSupport
;
339 ScsiBusDev
->DevicePath
= ParentDevicePath
;
340 if (ScsiBusDev
->ExtScsiSupport
) {
341 ScsiBusDev
->ExtScsiInterface
= ExtScsiInterface
;
343 ScsiBusDev
->ScsiInterface
= ScsiInterface
;
347 // Install EFI_SCSI_BUS_PROTOCOL to the controller handle, So ScsiBusDev could be
348 // retrieved on this controller handle. With ScsiBusDev, we can know which PassThru
349 // Protocol is present on the handle, UEFI ExtPassThru Protocol or EFI PassThru Protocol.
351 Status
= gBS
->InstallProtocolInterface (
353 &mScsiBusProtocolGuid
,
354 EFI_NATIVE_INTERFACE
,
355 &ScsiBusDev
->BusIdentify
357 if (EFI_ERROR (Status
)) {
362 // Go through here means Start() is re-invoked again, nothing special is required to do except
363 // picking up Host controller private information.
365 Status
= gBS
->OpenProtocol (
367 &mScsiBusProtocolGuid
,
368 (VOID
**) &BusIdentify
,
369 This
->DriverBindingHandle
,
371 EFI_OPEN_PROTOCOL_GET_PROTOCOL
374 if (EFI_ERROR (Status
)) {
377 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify
);
380 if (RemainingDevicePath
== NULL
) {
381 SetMem (ScsiTargetId
, TARGET_MAX_BYTES
,0xFF);
383 FromFirstTarget
= TRUE
;
385 if (ScsiBusDev
->ExtScsiSupport
) {
386 ScsiBusDev
->ExtScsiInterface
->GetTargetLun (ScsiBusDev
->ExtScsiInterface
, RemainingDevicePath
, &TargetId
, &Lun
);
388 ScsiBusDev
->ScsiInterface
->GetTargetLun (ScsiBusDev
->ScsiInterface
, RemainingDevicePath
, &ScsiTargetId
->ScsiId
.Scsi
, &Lun
);
392 while(ScanOtherPuns
) {
393 if (FromFirstTarget
) {
395 // Remaining Device Path is NULL, scan all the possible Puns in the
398 if (ScsiBusDev
->ExtScsiSupport
) {
399 Status
= ScsiBusDev
->ExtScsiInterface
->GetNextTargetLun (ScsiBusDev
->ExtScsiInterface
, &TargetId
, &Lun
);
401 Status
= ScsiBusDev
->ScsiInterface
->GetNextDevice (ScsiBusDev
->ScsiInterface
, &ScsiTargetId
->ScsiId
.Scsi
, &Lun
);
403 if (EFI_ERROR (Status
)) {
405 // no legal Pun and Lun found any more
410 ScanOtherPuns
= FALSE
;
413 // Avoid creating handle for the host adapter.
415 if (ScsiBusDev
->ExtScsiSupport
) {
416 if ((ScsiTargetId
->ScsiId
.Scsi
) == ScsiBusDev
->ExtScsiInterface
->Mode
->AdapterId
) {
420 if ((ScsiTargetId
->ScsiId
.Scsi
) == ScsiBusDev
->ScsiInterface
->Mode
->AdapterId
) {
425 // Scan for the scsi device, if it attaches to the scsi bus,
426 // then create handle and install scsi i/o protocol.
428 Status
= ScsiScanCreateDevice (This
, Controller
, ScsiTargetId
, Lun
, ScsiBusDev
);
430 FreePool (ScsiTargetId
);
435 if (ScsiBusDev
!= NULL
) {
436 FreePool (ScsiBusDev
);
439 if (ExtScsiSupport
) {
442 &gEfiExtScsiPassThruProtocolGuid
,
443 This
->DriverBindingHandle
,
446 if (!EFI_ERROR (PassThruStatus
)) {
449 &gEfiScsiPassThruProtocolGuid
,
450 This
->DriverBindingHandle
,
457 &gEfiScsiPassThruProtocolGuid
,
458 This
->DriverBindingHandle
,
466 Stop this driver on ControllerHandle.
468 This service is called by the EFI boot service DisconnectController().
469 In order to make drivers as small as possible, there are a few calling
470 restrictions for this service. DisconnectController() must follow these
471 calling restrictions. If any other agent wishes to call Stop() it must also
472 follow these calling restrictions.
474 @param This Protocol instance pointer.
475 @param ControllerHandle Handle of device to stop driver on
476 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
477 children is zero stop the entire bus driver.
478 @param ChildHandleBuffer List of Child Handles to Stop.
480 @retval EFI_SUCCESS This driver is removed ControllerHandle
481 @retval other This driver was not removed from this device
486 SCSIBusDriverBindingStop (
487 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
488 IN EFI_HANDLE Controller
,
489 IN UINTN NumberOfChildren
,
490 IN EFI_HANDLE
*ChildHandleBuffer
494 BOOLEAN AllChildrenStopped
;
496 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
497 SCSI_IO_DEV
*ScsiIoDevice
;
499 EFI_SCSI_BUS_PROTOCOL
*Scsidentifier
;
500 SCSI_BUS_DEVICE
*ScsiBusDev
;
502 if (NumberOfChildren
== 0) {
504 // Get the SCSI_BUS_DEVICE
506 Status
= gBS
->OpenProtocol (
508 &mScsiBusProtocolGuid
,
509 (VOID
**) &Scsidentifier
,
510 This
->DriverBindingHandle
,
512 EFI_OPEN_PROTOCOL_GET_PROTOCOL
515 if (EFI_ERROR (Status
)) {
516 return EFI_DEVICE_ERROR
;
519 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier
);
522 // Uninstall SCSI Bus Protocol
524 gBS
->UninstallProtocolInterface (
526 &mScsiBusProtocolGuid
,
527 &ScsiBusDev
->BusIdentify
531 // Close the bus driver
533 if (ScsiBusDev
->ExtScsiSupport
) {
536 &gEfiExtScsiPassThruProtocolGuid
,
537 This
->DriverBindingHandle
,
543 &gEfiScsiPassThruProtocolGuid
,
544 This
->DriverBindingHandle
,
551 &gEfiDevicePathProtocolGuid
,
552 This
->DriverBindingHandle
,
555 FreePool (ScsiBusDev
);
559 AllChildrenStopped
= TRUE
;
561 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
563 Status
= gBS
->OpenProtocol (
564 ChildHandleBuffer
[Index
],
565 &gEfiScsiIoProtocolGuid
,
567 This
->DriverBindingHandle
,
569 EFI_OPEN_PROTOCOL_GET_PROTOCOL
571 if (EFI_ERROR (Status
)) {
572 AllChildrenStopped
= FALSE
;
576 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (ScsiIo
);
578 // Close the child handle
580 if (ScsiIoDevice
->ExtScsiSupport
) {
581 Status
= gBS
->CloseProtocol (
583 &gEfiExtScsiPassThruProtocolGuid
,
584 This
->DriverBindingHandle
,
585 ChildHandleBuffer
[Index
]
589 Status
= gBS
->CloseProtocol (
591 &gEfiScsiPassThruProtocolGuid
,
592 This
->DriverBindingHandle
,
593 ChildHandleBuffer
[Index
]
597 Status
= gBS
->UninstallMultipleProtocolInterfaces (
598 ChildHandleBuffer
[Index
],
599 &gEfiDevicePathProtocolGuid
,
600 ScsiIoDevice
->DevicePath
,
601 &gEfiScsiIoProtocolGuid
,
602 &ScsiIoDevice
->ScsiIo
,
605 if (EFI_ERROR (Status
)) {
606 AllChildrenStopped
= FALSE
;
607 if (ScsiIoDevice
->ExtScsiSupport
) {
610 &gEfiExtScsiPassThruProtocolGuid
,
612 This
->DriverBindingHandle
,
613 ChildHandleBuffer
[Index
],
614 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
619 &gEfiScsiPassThruProtocolGuid
,
621 This
->DriverBindingHandle
,
622 ChildHandleBuffer
[Index
],
623 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
627 FreePool (ScsiIoDevice
);
631 if (!AllChildrenStopped
) {
632 return EFI_DEVICE_ERROR
;
640 Retrieves the device type information of the SCSI Controller.
642 @param This Protocol instance pointer.
643 @param DeviceType A pointer to the device type information retrieved from
646 @retval EFI_SUCCESS Retrieves the device type information successfully.
647 @retval EFI_INVALID_PARAMETER The DeviceType is NULL.
653 IN EFI_SCSI_IO_PROTOCOL
*This
,
654 OUT UINT8
*DeviceType
657 SCSI_IO_DEV
*ScsiIoDevice
;
659 if (DeviceType
== NULL
) {
660 return EFI_INVALID_PARAMETER
;
663 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
664 *DeviceType
= ScsiIoDevice
->ScsiDeviceType
;
670 Retrieves the device location in the SCSI channel.
672 @param This Protocol instance pointer.
673 @param Target A pointer to the Target ID of a SCSI device
675 @param Lun A pointer to the LUN of the SCSI device on
678 @retval EFI_SUCCESS Retrieves the device location successfully.
679 @retval EFI_INVALID_PARAMETER The Target or Lun is NULL.
684 ScsiGetDeviceLocation (
685 IN EFI_SCSI_IO_PROTOCOL
*This
,
686 IN OUT UINT8
**Target
,
690 SCSI_IO_DEV
*ScsiIoDevice
;
692 if (Target
== NULL
|| Lun
== NULL
) {
693 return EFI_INVALID_PARAMETER
;
696 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
698 CopyMem (*Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
700 *Lun
= ScsiIoDevice
->Lun
;
706 Resets the SCSI Bus that the SCSI Controller is attached to.
708 @param This Protocol instance pointer.
710 @retval EFI_SUCCESS The SCSI bus is reset successfully.
711 @retval EFI_DEVICE_ERROR Errors encountered when resetting the SCSI bus.
712 @retval EFI_UNSUPPORTED The bus reset operation is not supported by the
713 SCSI Host Controller.
714 @retval EFI_TIMEOUT A timeout occurred while attempting to reset
720 IN EFI_SCSI_IO_PROTOCOL
*This
723 SCSI_IO_DEV
*ScsiIoDevice
;
725 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
727 if (ScsiIoDevice
->ExtScsiSupport
){
728 return ScsiIoDevice
->ExtScsiPassThru
->ResetChannel (ScsiIoDevice
->ExtScsiPassThru
);
730 return ScsiIoDevice
->ScsiPassThru
->ResetChannel (ScsiIoDevice
->ScsiPassThru
);
736 Resets the SCSI Controller that the device handle specifies.
738 @param This Protocol instance pointer.
740 @retval EFI_SUCCESS Reset the SCSI controller successfully.
741 @retval EFI_DEVICE_ERROR Errors are encountered when resetting the SCSI Controller.
742 @retval EFI_UNSUPPORTED The SCSI bus does not support a device reset operation.
743 @retval EFI_TIMEOUT A timeout occurred while attempting to reset the
749 IN EFI_SCSI_IO_PROTOCOL
*This
752 SCSI_IO_DEV
*ScsiIoDevice
;
753 UINT8 Target
[TARGET_MAX_BYTES
];
755 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
756 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
759 if (ScsiIoDevice
->ExtScsiSupport
) {
760 return ScsiIoDevice
->ExtScsiPassThru
->ResetTargetLun (
761 ScsiIoDevice
->ExtScsiPassThru
,
766 return ScsiIoDevice
->ScsiPassThru
->ResetTarget (
767 ScsiIoDevice
->ScsiPassThru
,
768 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
776 Sends a SCSI Request Packet to the SCSI Controller for execution.
778 @param This Protocol instance pointer.
779 @param CommandPacket The SCSI request packet to send to the SCSI
780 Controller specified by the device handle.
781 @param Event If the SCSI bus where the SCSI device is attached
782 does not support non-blocking I/O, then Event is
783 ignored, and blocking I/O is performed.
784 If Event is NULL, then blocking I/O is performed.
785 If Event is not NULL and non-blocking I/O is
786 supported, then non-blocking I/O is performed,
787 and Event will be signaled when the SCSI Request
790 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host
791 successfully, and TransferLength bytes were
792 transferred to/from DataBuffer.See
793 HostAdapterStatus, TargetStatus,
794 SenseDataLength, and SenseData in that order
795 for additional status information.
796 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
797 but the entire DataBuffer could not be transferred.
798 The actual number of bytes transferred is returned
799 in TransferLength. See HostAdapterStatus,
800 TargetStatus, SenseDataLength, and SenseData in
801 that order for additional status information.
802 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
803 there are too many SCSI Command Packets already
804 queued.The caller may retry again later.
805 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
806 the SCSI Request Packet. See HostAdapterStatus,
807 TargetStatus, SenseDataLength, and SenseData in
808 that order for additional status information.
809 @retval EFI_INVALID_PARAMETER The contents of CommandPacket are invalid.
810 The SCSI Request Packet was not sent, so no
811 additional status information is available.
812 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
813 is not supported by the SCSI initiator(i.e., SCSI
814 Host Controller). The SCSI Request Packet was not
815 sent, so no additional status information is
817 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
818 Request Packet to execute. See HostAdapterStatus,
819 TargetStatus, SenseDataLength, and SenseData in
820 that order for additional status information.
824 ScsiExecuteSCSICommand (
825 IN EFI_SCSI_IO_PROTOCOL
*This
,
826 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
827 IN EFI_EVENT Event OPTIONAL
830 SCSI_IO_DEV
*ScsiIoDevice
;
832 UINT8 Target
[TARGET_MAX_BYTES
];
833 EFI_EVENT PacketEvent
;
834 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ExtRequestPacket
;
835 SCSI_EVENT_DATA EventData
;
839 if (Packet
== NULL
) {
840 return EFI_INVALID_PARAMETER
;
843 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
844 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
846 if (ScsiIoDevice
->ExtScsiSupport
) {
847 ExtRequestPacket
= (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*) Packet
;
848 Status
= ScsiIoDevice
->ExtScsiPassThru
->PassThru (
849 ScsiIoDevice
->ExtScsiPassThru
,
857 mWorkingBuffer
= AllocatePool (sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
859 if (mWorkingBuffer
== NULL
) {
860 return EFI_DEVICE_ERROR
;
864 // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.
866 Status
= ScsiioToPassThruPacket(Packet
, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)mWorkingBuffer
);
867 if (EFI_ERROR(Status
)) {
868 FreePool(mWorkingBuffer
);
872 if (((ScsiIoDevice
->ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO
) != 0) && (Event
!= NULL
)) {
873 EventData
.Data1
= (VOID
*)Packet
;
874 EventData
.Data2
= Event
;
878 Status
= gBS
->CreateEvent (
885 if (EFI_ERROR(Status
)) {
886 FreePool(mWorkingBuffer
);
890 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
891 ScsiIoDevice
->ScsiPassThru
,
892 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
898 if (EFI_ERROR(Status
)) {
899 FreePool(mWorkingBuffer
);
900 gBS
->CloseEvent(PacketEvent
);
906 // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert
907 // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.
909 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
910 ScsiIoDevice
->ScsiPassThru
,
911 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
916 if (EFI_ERROR(Status
)) {
917 FreePool(mWorkingBuffer
);
921 PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)mWorkingBuffer
,Packet
);
923 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
924 // free mWorkingBuffer.
926 FreePool(mWorkingBuffer
);
934 Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.
936 @param This Protocol instance pointer
937 @param Controller Controller handle
938 @param TargetId Tartget to be scanned
939 @param Lun The Lun of the SCSI device on the SCSI channel.
940 @param ScsiBusDev The pointer of SCSI_BUS_DEVICE
942 @retval EFI_SUCCESS Successfully to discover the device and attach
943 ScsiIoProtocol to it.
944 @retval EFI_OUT_OF_RESOURCES Fail to discover the device.
949 ScsiScanCreateDevice (
950 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
951 IN EFI_HANDLE Controller
,
952 IN SCSI_TARGET_ID
*TargetId
,
954 IN OUT SCSI_BUS_DEVICE
*ScsiBusDev
958 SCSI_IO_DEV
*ScsiIoDevice
;
959 EFI_DEVICE_PATH_PROTOCOL
*ScsiDevicePath
;
961 ScsiIoDevice
= AllocateZeroPool (sizeof (SCSI_IO_DEV
));
962 if (ScsiIoDevice
== NULL
) {
963 return EFI_OUT_OF_RESOURCES
;
966 ScsiIoDevice
->Signature
= SCSI_IO_DEV_SIGNATURE
;
967 CopyMem(&ScsiIoDevice
->Pun
, TargetId
, TARGET_MAX_BYTES
);
968 ScsiIoDevice
->Lun
= Lun
;
970 if (ScsiBusDev
->ExtScsiSupport
) {
971 ScsiIoDevice
->ExtScsiPassThru
= ScsiBusDev
->ExtScsiInterface
;
972 ScsiIoDevice
->ExtScsiSupport
= TRUE
;
973 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ExtScsiPassThru
->Mode
->IoAlign
;
976 ScsiIoDevice
->ScsiPassThru
= ScsiBusDev
->ScsiInterface
;
977 ScsiIoDevice
->ExtScsiSupport
= FALSE
;
978 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ScsiPassThru
->Mode
->IoAlign
;
981 ScsiIoDevice
->ScsiIo
.GetDeviceType
= ScsiGetDeviceType
;
982 ScsiIoDevice
->ScsiIo
.GetDeviceLocation
= ScsiGetDeviceLocation
;
983 ScsiIoDevice
->ScsiIo
.ResetBus
= ScsiResetBus
;
984 ScsiIoDevice
->ScsiIo
.ResetDevice
= ScsiResetDevice
;
985 ScsiIoDevice
->ScsiIo
.ExecuteScsiCommand
= ScsiExecuteSCSICommand
;
988 if (!DiscoverScsiDevice (ScsiIoDevice
)) {
989 FreePool (ScsiIoDevice
);
990 return EFI_OUT_OF_RESOURCES
;
996 ScsiDevicePath
= NULL
;
997 if (ScsiIoDevice
->ExtScsiSupport
){
998 Status
= ScsiIoDevice
->ExtScsiPassThru
->BuildDevicePath (
999 ScsiIoDevice
->ExtScsiPassThru
,
1000 &ScsiIoDevice
->Pun
.ScsiId
.ExtScsi
[0],
1004 if (Status
== EFI_OUT_OF_RESOURCES
) {
1005 FreePool (ScsiIoDevice
);
1009 Status
= ScsiIoDevice
->ScsiPassThru
->BuildDevicePath (
1010 ScsiIoDevice
->ScsiPassThru
,
1011 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
1015 if (Status
== EFI_OUT_OF_RESOURCES
) {
1016 FreePool (ScsiIoDevice
);
1021 ScsiIoDevice
->DevicePath
= AppendDevicePathNode (
1022 ScsiBusDev
->DevicePath
,
1026 // The memory space for ScsiDevicePath is allocated in
1027 // ScsiPassThru->BuildDevicePath() function; It is no longer used
1028 // after EfiAppendDevicePathNode,so free the memory it occupies.
1030 FreePool (ScsiDevicePath
);
1032 if (ScsiIoDevice
->DevicePath
== NULL
) {
1033 FreePool (ScsiIoDevice
);
1034 return EFI_OUT_OF_RESOURCES
;
1037 Status
= gBS
->InstallMultipleProtocolInterfaces (
1038 &ScsiIoDevice
->Handle
,
1039 &gEfiDevicePathProtocolGuid
,
1040 ScsiIoDevice
->DevicePath
,
1041 &gEfiScsiIoProtocolGuid
,
1042 &ScsiIoDevice
->ScsiIo
,
1045 if (EFI_ERROR (Status
)) {
1046 FreePool (ScsiIoDevice
);
1047 return EFI_OUT_OF_RESOURCES
;
1049 if (ScsiBusDev
->ExtScsiSupport
) {
1052 &gEfiExtScsiPassThruProtocolGuid
,
1053 (VOID
**) &(ScsiBusDev
->ExtScsiInterface
),
1054 This
->DriverBindingHandle
,
1055 ScsiIoDevice
->Handle
,
1056 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1061 &gEfiScsiPassThruProtocolGuid
,
1062 (VOID
**) &(ScsiBusDev
->ScsiInterface
),
1063 This
->DriverBindingHandle
,
1064 ScsiIoDevice
->Handle
,
1065 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1074 Discovery SCSI Device
1076 @param ScsiIoDevice The pointer of SCSI_IO_DEV
1078 @retval TRUE Find SCSI Device and verify it.
1079 @retval FALSE Unable to find SCSI Device.
1083 DiscoverScsiDevice (
1084 IN OUT SCSI_IO_DEV
*ScsiIoDevice
1088 UINT32 InquiryDataLength
;
1089 UINT8 SenseDataLength
;
1090 UINT8 HostAdapterStatus
;
1092 EFI_SCSI_SENSE_DATA SenseData
;
1093 EFI_SCSI_INQUIRY_DATA InquiryData
;
1095 HostAdapterStatus
= 0;
1098 // Using Inquiry command to scan for the device
1100 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1101 SenseDataLength
= sizeof (EFI_SCSI_SENSE_DATA
);
1103 Status
= ScsiInquiryCommand (
1104 &ScsiIoDevice
->ScsiIo
,
1105 EFI_TIMER_PERIOD_SECONDS (1),
1106 (VOID
*) &SenseData
,
1110 (VOID
*) &InquiryData
,
1114 if (EFI_ERROR (Status
)) {
1118 // Retrieved inquiry data successfully
1120 if ((InquiryData
.Peripheral_Qualifier
!= 0) &&
1121 (InquiryData
.Peripheral_Qualifier
!= 3)) {
1125 if (InquiryData
.Peripheral_Qualifier
== 3) {
1126 if (InquiryData
.Peripheral_Type
!= 0x1f) {
1131 if (0x1e >= InquiryData
.Peripheral_Type
&& InquiryData
.Peripheral_Type
>= 0xa) {
1136 // valid device type and peripheral qualifier combination.
1138 ScsiIoDevice
->ScsiDeviceType
= InquiryData
.Peripheral_Type
;
1139 ScsiIoDevice
->RemovableDevice
= InquiryData
.RMB
;
1140 if (InquiryData
.Version
== 0) {
1141 ScsiIoDevice
->ScsiVersion
= 0;
1144 // ANSI-approved version
1146 ScsiIoDevice
->ScsiVersion
= (UINT8
) (InquiryData
.Version
& 0x03);
1154 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.
1156 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1157 @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1162 ScsiioToPassThruPacket (
1163 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
1164 OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
1168 //EFI 1.10 doesn't support Bi-Direction Command.
1170 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL
) {
1171 return EFI_UNSUPPORTED
;
1174 ZeroMem (CommandPacket
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1176 CommandPacket
->Timeout
= Packet
->Timeout
;
1177 CommandPacket
->Cdb
= Packet
->Cdb
;
1178 CommandPacket
->CdbLength
= Packet
->CdbLength
;
1179 CommandPacket
->DataDirection
= Packet
->DataDirection
;
1180 CommandPacket
->HostAdapterStatus
= Packet
->HostAdapterStatus
;
1181 CommandPacket
->TargetStatus
= Packet
->TargetStatus
;
1182 CommandPacket
->SenseData
= Packet
->SenseData
;
1183 CommandPacket
->SenseDataLength
= Packet
->SenseDataLength
;
1185 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1186 CommandPacket
->DataBuffer
= Packet
->InDataBuffer
;
1187 CommandPacket
->TransferLength
= Packet
->InTransferLength
;
1188 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1189 CommandPacket
->DataBuffer
= Packet
->OutDataBuffer
;
1190 CommandPacket
->TransferLength
= Packet
->OutTransferLength
;
1197 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.
1199 @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1200 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1205 PassThruToScsiioPacket (
1206 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
1207 OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
1210 Packet
->Timeout
= ScsiPacket
->Timeout
;
1211 Packet
->Cdb
= ScsiPacket
->Cdb
;
1212 Packet
->CdbLength
= ScsiPacket
->CdbLength
;
1213 Packet
->DataDirection
= ScsiPacket
->DataDirection
;
1214 Packet
->HostAdapterStatus
= ScsiPacket
->HostAdapterStatus
;
1215 Packet
->TargetStatus
= ScsiPacket
->TargetStatus
;
1216 Packet
->SenseData
= ScsiPacket
->SenseData
;
1217 Packet
->SenseDataLength
= ScsiPacket
->SenseDataLength
;
1219 if (ScsiPacket
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1220 Packet
->InDataBuffer
= ScsiPacket
->DataBuffer
;
1221 Packet
->InTransferLength
= ScsiPacket
->TransferLength
;
1222 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1223 Packet
->OutDataBuffer
= ScsiPacket
->DataBuffer
;
1224 Packet
->OutTransferLength
= ScsiPacket
->TransferLength
;
1231 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
1234 @param Event The instance of EFI_EVENT.
1235 @param Context The parameter passed in.
1245 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
;
1246 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
;
1247 EFI_EVENT CallerEvent
;
1248 SCSI_EVENT_DATA
*PassData
;
1250 PassData
= (SCSI_EVENT_DATA
*)Context
;
1251 Packet
= (EFI_SCSI_IO_SCSI_REQUEST_PACKET
*)PassData
->Data1
;
1252 ScsiPacket
= (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)mWorkingBuffer
;
1255 // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.
1257 PassThruToScsiioPacket(ScsiPacket
, Packet
);
1260 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1261 // free mWorkingBuffer.
1263 gBS
->FreePool(mWorkingBuffer
);
1266 // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.
1268 CallerEvent
= PassData
->Data2
;
1269 gBS
->CloseEvent(Event
);
1270 gBS
->SignalEvent(CallerEvent
);