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 #include <Protocol/ScsiPassThru.h>
21 #include <Protocol/ScsiPassThruExt.h>
22 #include <Protocol/ScsiIo.h>
23 #include <Protocol/ComponentName.h>
24 #include <Protocol/DriverBinding.h>
25 #include <Protocol/DevicePath.h>
27 #include <Library/DebugLib.h>
28 #include <Library/UefiDriverEntryPoint.h>
29 #include <Library/UefiLib.h>
30 #include <Library/BaseMemoryLib.h>
31 #include <Library/MemoryAllocationLib.h>
32 #include <Library/ScsiLib.h>
33 #include <Library/UefiBootServicesTableLib.h>
34 #include <Library/DevicePathLib.h>
38 EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding
= {
39 SCSIBusDriverBindingSupported
,
40 SCSIBusDriverBindingStart
,
41 SCSIBusDriverBindingStop
,
49 // The ScsiBusProtocol is just used to locate ScsiBusDev
50 // structure in the SCSIBusDriverBindingStop(). Then we can
51 // Close all opened protocols and release this structure.
53 STATIC EFI_GUID mScsiBusProtocolGuid
= EFI_SCSI_BUS_PROTOCOL_GUID
;
55 STATIC VOID
*WorkingBuffer
;
60 ScsiioToPassThruPacket (
61 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
62 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
70 PassThruToScsiioPacket (
71 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
72 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
85 The user Entry Point for module ScsiBus. The user code starts with this function.
87 @param[in] ImageHandle The firmware allocated handle for the EFI image.
88 @param[in] SystemTable A pointer to the EFI System Table.
90 @retval EFI_SUCCESS The entry point is executed successfully.
91 @retval other Some error occurs when executing this entry point.
97 IN EFI_HANDLE ImageHandle
,
98 IN EFI_SYSTEM_TABLE
*SystemTable
104 // Install driver model protocol(s).
106 Status
= EfiLibInstallDriverBindingComponentName2 (
109 &gSCSIBusDriverBinding
,
111 &gScsiBusComponentName
,
112 &gScsiBusComponentName2
114 ASSERT_EFI_ERROR (Status
);
121 SCSIBusDriverBindingSupported (
122 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
123 IN EFI_HANDLE Controller
,
124 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
130 Test to see if this driver supports ControllerHandle. Any ControllerHandle
131 that has ExtScsiPassThruProtocol/ScsiPassThruProtocol installed will be supported.
135 This - Protocol instance pointer.
136 Controller - Handle of device to test
137 RemainingDevicePath - Not used
141 EFI_SUCCESS - This driver supports this device.
142 EFI_UNSUPPORTED - This driver does not support this device.
148 EFI_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
149 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtPassThru
;
151 // Check for the existence of Extended SCSI Pass Thru Protocol and SCSI Pass Thru Protocol
153 Status
= gBS
->OpenProtocol (
155 &gEfiExtScsiPassThruProtocolGuid
,
156 (VOID
**)&ExtPassThru
,
157 This
->DriverBindingHandle
,
159 EFI_OPEN_PROTOCOL_BY_DRIVER
162 if (Status
== EFI_ALREADY_STARTED
) {
166 if (EFI_ERROR (Status
)) {
167 Status
= gBS
->OpenProtocol (
169 &gEfiScsiPassThruProtocolGuid
,
171 This
->DriverBindingHandle
,
173 EFI_OPEN_PROTOCOL_BY_DRIVER
176 if (Status
== EFI_ALREADY_STARTED
) {
180 if (EFI_ERROR (Status
)) {
186 &gEfiScsiPassThruProtocolGuid
,
187 This
->DriverBindingHandle
,
195 &gEfiExtScsiPassThruProtocolGuid
,
196 This
->DriverBindingHandle
,
205 SCSIBusDriverBindingStart (
206 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
207 IN EFI_HANDLE Controller
,
208 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
213 Starting the SCSI Bus Driver
216 This - Protocol instance pointer.
217 Controller - Handle of device to test
218 RemainingDevicePath - Not used
221 EFI_SUCCESS - This driver supports this device.
222 EFI_UNSUPPORTED - This driver does not support this device.
223 EFI_DEVICE_ERROR - This driver cannot be started due to device Error
229 BOOLEAN ScanOtherPuns
;
230 BOOLEAN FromFirstTarget
;
231 BOOLEAN ExtScsiSupport
;
233 EFI_STATUS DevicePathStatus
;
234 EFI_STATUS PassThruStatus
;
235 SCSI_BUS_DEVICE
*ScsiBusDev
;
236 SCSI_TARGET_ID
*ScsiTargetId
;
237 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
238 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiInterface
;
239 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiInterface
;
240 EFI_SCSI_BUS_PROTOCOL
*BusIdentify
;
244 ScanOtherPuns
= TRUE
;
245 FromFirstTarget
= FALSE
;
246 ExtScsiSupport
= FALSE
;
247 PassThruStatus
= EFI_SUCCESS
;
249 ScsiTargetId
= AllocateZeroPool(sizeof(SCSI_TARGET_ID
));
250 if (ScsiTargetId
== NULL
) {
251 return EFI_OUT_OF_RESOURCES
;
254 TargetId
= &ScsiTargetId
->ScsiId
.ExtScsi
[0];
256 DevicePathStatus
= gBS
->OpenProtocol (
258 &gEfiDevicePathProtocolGuid
,
259 (VOID
**) &ParentDevicePath
,
260 This
->DriverBindingHandle
,
262 EFI_OPEN_PROTOCOL_BY_DRIVER
264 if (EFI_ERROR (DevicePathStatus
) && (DevicePathStatus
!= EFI_ALREADY_STARTED
)) {
265 return DevicePathStatus
;
269 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
270 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
271 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
273 Status
= gBS
->OpenProtocol (
275 &gEfiExtScsiPassThruProtocolGuid
,
276 (VOID
**) &ExtScsiInterface
,
277 This
->DriverBindingHandle
,
279 EFI_OPEN_PROTOCOL_BY_DRIVER
282 // Fail to open UEFI ExtendPassThru Protocol, then try to open EFI PassThru Protocol instead.
284 if (EFI_ERROR(Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
285 Status
= gBS
->OpenProtocol (
287 &gEfiScsiPassThruProtocolGuid
,
288 (VOID
**) &ScsiInterface
,
289 This
->DriverBindingHandle
,
291 EFI_OPEN_PROTOCOL_BY_DRIVER
294 // Fail to open EFI PassThru Protocol, Close the DevicePathProtocol if it is opened by this time.
296 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
297 if (!EFI_ERROR(DevicePathStatus
)) {
300 &gEfiDevicePathProtocolGuid
,
301 This
->DriverBindingHandle
,
309 // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol
310 // with BY_DRIVER if it is also present on the handle. The intent is to prevent
311 // another SCSI Bus Driver to work on the same host handle.
313 ExtScsiSupport
= TRUE
;
314 PassThruStatus
= gBS
->OpenProtocol (
316 &gEfiScsiPassThruProtocolGuid
,
317 (VOID
**) &ScsiInterface
,
318 This
->DriverBindingHandle
,
320 EFI_OPEN_PROTOCOL_BY_DRIVER
324 if (Status
!= EFI_ALREADY_STARTED
) {
326 // Go through here means either ExtPassThru or PassThru Protocol is successfully opened
327 // on this handle for this time. Then construct Host controller private data.
330 ScsiBusDev
= AllocateZeroPool(sizeof(SCSI_BUS_DEVICE
));
331 if (ScsiBusDev
== NULL
) {
332 Status
= EFI_OUT_OF_RESOURCES
;
335 ScsiBusDev
->Signature
= SCSI_BUS_DEVICE_SIGNATURE
;
336 ScsiBusDev
->ExtScsiSupport
= ExtScsiSupport
;
337 ScsiBusDev
->DevicePath
= ParentDevicePath
;
338 if (ScsiBusDev
->ExtScsiSupport
) {
339 ScsiBusDev
->ExtScsiInterface
= ExtScsiInterface
;
341 ScsiBusDev
->ScsiInterface
= ScsiInterface
;
345 // Install EFI_SCSI_BUS_PROTOCOL to the controller handle, So ScsiBusDev could be
346 // retrieved on this controller handle. With ScsiBusDev, we can know which PassThru
347 // Protocol is present on the handle, UEFI ExtPassThru Protocol or EFI PassThru Protocol.
349 Status
= gBS
->InstallProtocolInterface (
351 &mScsiBusProtocolGuid
,
352 EFI_NATIVE_INTERFACE
,
353 &ScsiBusDev
->BusIdentify
355 if (EFI_ERROR (Status
)) {
360 // Go through here means Start() is re-invoked again, nothing special is required to do except
361 // picking up Host controller private information.
363 Status
= gBS
->OpenProtocol (
365 &mScsiBusProtocolGuid
,
366 (VOID
**) &BusIdentify
,
367 This
->DriverBindingHandle
,
369 EFI_OPEN_PROTOCOL_GET_PROTOCOL
372 if (EFI_ERROR (Status
)) {
375 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify
);
378 if (RemainingDevicePath
== NULL
) {
379 SetMem (ScsiTargetId
, TARGET_MAX_BYTES
,0xFF);
381 FromFirstTarget
= TRUE
;
383 if (ScsiBusDev
->ExtScsiSupport
) {
384 ScsiBusDev
->ExtScsiInterface
->GetTargetLun (ScsiBusDev
->ExtScsiInterface
, RemainingDevicePath
, &TargetId
, &Lun
);
386 ScsiBusDev
->ScsiInterface
->GetTargetLun (ScsiBusDev
->ScsiInterface
, RemainingDevicePath
, &ScsiTargetId
->ScsiId
.Scsi
, &Lun
);
390 while(ScanOtherPuns
) {
391 if (FromFirstTarget
) {
393 // Remaining Device Path is NULL, scan all the possible Puns in the
396 if (ScsiBusDev
->ExtScsiSupport
) {
397 Status
= ScsiBusDev
->ExtScsiInterface
->GetNextTargetLun (ScsiBusDev
->ExtScsiInterface
, &TargetId
, &Lun
);
399 Status
= ScsiBusDev
->ScsiInterface
->GetNextDevice (ScsiBusDev
->ScsiInterface
, &ScsiTargetId
->ScsiId
.Scsi
, &Lun
);
401 if (EFI_ERROR (Status
)) {
403 // no legal Pun and Lun found any more
408 ScanOtherPuns
= FALSE
;
411 // Avoid creating handle for the host adapter.
413 if (ScsiBusDev
->ExtScsiSupport
) {
414 if ((ScsiTargetId
->ScsiId
.Scsi
) == ScsiBusDev
->ExtScsiInterface
->Mode
->AdapterId
) {
418 if ((ScsiTargetId
->ScsiId
.Scsi
) == ScsiBusDev
->ScsiInterface
->Mode
->AdapterId
) {
423 // Scan for the scsi device, if it attaches to the scsi bus,
424 // then create handle and install scsi i/o protocol.
426 Status
= ScsiScanCreateDevice (This
, Controller
, ScsiTargetId
, Lun
, ScsiBusDev
);
428 gBS
->FreePool (ScsiTargetId
);
433 if (ScsiBusDev
!= NULL
) {
434 gBS
->FreePool (ScsiBusDev
);
437 if (ExtScsiSupport
) {
440 &gEfiExtScsiPassThruProtocolGuid
,
441 This
->DriverBindingHandle
,
444 if (!EFI_ERROR (PassThruStatus
)) {
447 &gEfiScsiPassThruProtocolGuid
,
448 This
->DriverBindingHandle
,
455 &gEfiScsiPassThruProtocolGuid
,
456 This
->DriverBindingHandle
,
465 SCSIBusDriverBindingStop (
466 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
467 IN EFI_HANDLE Controller
,
468 IN UINTN NumberOfChildren
,
469 IN EFI_HANDLE
*ChildHandleBuffer
475 Stop this driver on ControllerHandle. Support stoping any child handles
476 created by this driver.
480 This - Protocol instance pointer.
481 Controller - Handle of device to stop driver on
482 NumberOfChildren - Number of Children in the ChildHandleBuffer
483 ChildHandleBuffer - List of handles for the children we need to stop.
492 BOOLEAN AllChildrenStopped
;
494 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
495 SCSI_IO_DEV
*ScsiIoDevice
;
497 EFI_SCSI_BUS_PROTOCOL
*Scsidentifier
;
498 SCSI_BUS_DEVICE
*ScsiBusDev
;
500 if (NumberOfChildren
== 0) {
502 // Get the SCSI_BUS_DEVICE
504 Status
= gBS
->OpenProtocol (
506 &mScsiBusProtocolGuid
,
507 (VOID
**) &Scsidentifier
,
508 This
->DriverBindingHandle
,
510 EFI_OPEN_PROTOCOL_GET_PROTOCOL
513 if (EFI_ERROR (Status
)) {
514 return EFI_DEVICE_ERROR
;
517 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier
);
520 // Uninstall SCSI Bus Protocol
522 gBS
->UninstallProtocolInterface (
524 &mScsiBusProtocolGuid
,
525 &ScsiBusDev
->BusIdentify
529 // Close the bus driver
531 if (ScsiBusDev
->ExtScsiSupport
) {
534 &gEfiExtScsiPassThruProtocolGuid
,
535 This
->DriverBindingHandle
,
541 &gEfiScsiPassThruProtocolGuid
,
542 This
->DriverBindingHandle
,
549 &gEfiDevicePathProtocolGuid
,
550 This
->DriverBindingHandle
,
553 gBS
->FreePool (ScsiBusDev
);
557 AllChildrenStopped
= TRUE
;
559 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
561 Status
= gBS
->OpenProtocol (
562 ChildHandleBuffer
[Index
],
563 &gEfiScsiIoProtocolGuid
,
565 This
->DriverBindingHandle
,
567 EFI_OPEN_PROTOCOL_GET_PROTOCOL
569 if (EFI_ERROR (Status
)) {
570 AllChildrenStopped
= FALSE
;
574 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (ScsiIo
);
576 // Close the child handle
578 if (ScsiIoDevice
->ExtScsiSupport
) {
579 Status
= gBS
->CloseProtocol (
581 &gEfiExtScsiPassThruProtocolGuid
,
582 This
->DriverBindingHandle
,
583 ChildHandleBuffer
[Index
]
587 Status
= gBS
->CloseProtocol (
589 &gEfiScsiPassThruProtocolGuid
,
590 This
->DriverBindingHandle
,
591 ChildHandleBuffer
[Index
]
595 Status
= gBS
->UninstallMultipleProtocolInterfaces (
596 ChildHandleBuffer
[Index
],
597 &gEfiDevicePathProtocolGuid
,
598 ScsiIoDevice
->DevicePath
,
599 &gEfiScsiIoProtocolGuid
,
600 &ScsiIoDevice
->ScsiIo
,
603 if (EFI_ERROR (Status
)) {
604 AllChildrenStopped
= FALSE
;
605 if (ScsiIoDevice
->ExtScsiSupport
) {
608 &gEfiExtScsiPassThruProtocolGuid
,
610 This
->DriverBindingHandle
,
611 ChildHandleBuffer
[Index
],
612 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
617 &gEfiScsiPassThruProtocolGuid
,
619 This
->DriverBindingHandle
,
620 ChildHandleBuffer
[Index
],
621 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
625 gBS
->FreePool (ScsiIoDevice
);
629 if (!AllChildrenStopped
) {
630 return EFI_DEVICE_ERROR
;
639 IN EFI_SCSI_IO_PROTOCOL
*This
,
640 OUT UINT8
*DeviceType
646 Retrieves the device type information of the SCSI Controller.
650 This - Protocol instance pointer.
651 DeviceType - A pointer to the device type information
652 retrieved from the SCSI Controller.
656 EFI_SUCCESS - Retrieves the device type information successfully.
657 EFI_INVALID_PARAMETER - The DeviceType is NULL.
661 SCSI_IO_DEV
*ScsiIoDevice
;
663 if (DeviceType
== NULL
) {
664 return EFI_INVALID_PARAMETER
;
667 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
668 *DeviceType
= ScsiIoDevice
->ScsiDeviceType
;
674 ScsiGetDeviceLocation (
675 IN EFI_SCSI_IO_PROTOCOL
*This
,
676 IN OUT UINT8
**Target
,
683 Retrieves the device location in the SCSI channel.
687 This - Protocol instance pointer.
688 Target - A pointer to the Target Array which represents ID of a SCSI device
690 Lun - A pointer to the LUN of the SCSI device on
695 EFI_SUCCESS - Retrieves the device location successfully.
696 EFI_INVALID_PARAMETER - The Target or Lun is NULL.
700 SCSI_IO_DEV
*ScsiIoDevice
;
702 if (Target
== NULL
|| Lun
== NULL
) {
703 return EFI_INVALID_PARAMETER
;
706 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
708 CopyMem (*Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
710 *Lun
= ScsiIoDevice
->Lun
;
718 IN EFI_SCSI_IO_PROTOCOL
*This
724 Resets the SCSI Bus that the SCSI Controller is attached to.
728 This - Protocol instance pointer.
732 EFI_SUCCESS - The SCSI bus is reset successfully.
733 EFI_DEVICE_ERROR - Errors encountered when resetting the SCSI bus.
734 EFI_UNSUPPORTED - The bus reset operation is not supported by the
735 SCSI Host Controller.
736 EFI_TIMEOUT - A timeout occurred while attempting to reset
740 SCSI_IO_DEV
*ScsiIoDevice
;
742 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
744 if (ScsiIoDevice
->ExtScsiSupport
){
745 return ScsiIoDevice
->ExtScsiPassThru
->ResetChannel (ScsiIoDevice
->ExtScsiPassThru
);
747 return ScsiIoDevice
->ScsiPassThru
->ResetChannel (ScsiIoDevice
->ScsiPassThru
);
754 IN EFI_SCSI_IO_PROTOCOL
*This
760 Resets the SCSI Controller that the device handle specifies.
764 This - Protocol instance pointer.
768 EFI_SUCCESS - Reset the SCSI controller successfully.
769 EFI_DEVICE_ERROR - Errors are encountered when resetting the
771 EFI_UNSUPPORTED - The SCSI bus does not support a device
773 EFI_TIMEOUT - A timeout occurred while attempting to
774 reset the SCSI Controller.
777 SCSI_IO_DEV
*ScsiIoDevice
;
778 UINT8 Target
[TARGET_MAX_BYTES
];
780 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
781 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
784 if (ScsiIoDevice
->ExtScsiSupport
) {
785 return ScsiIoDevice
->ExtScsiPassThru
->ResetTargetLun (
786 ScsiIoDevice
->ExtScsiPassThru
,
791 return ScsiIoDevice
->ScsiPassThru
->ResetTarget (
792 ScsiIoDevice
->ScsiPassThru
,
793 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
801 ScsiExecuteSCSICommand (
802 IN EFI_SCSI_IO_PROTOCOL
*This
,
803 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
804 IN EFI_EVENT Event OPTIONAL
810 Sends a SCSI Request Packet to the SCSI Controller for execution.
814 This - Protocol instance pointer.
815 Packet - The SCSI request packet to send to the SCSI
816 Controller specified by the device handle.
817 Event - If the SCSI bus where the SCSI device is attached
818 does not support non-blocking I/O, then Event is
819 ignored, and blocking I/O is performed.
820 If Event is NULL, then blocking I/O is performed.
821 If Event is not NULL and non-blocking I/O is
822 supported, then non-blocking I/O is performed,
823 and Event will be signaled when the SCSI Request
827 EFI_SUCCESS - The SCSI Request Packet was sent by the host
828 successfully, and TransferLength bytes were
829 transferred to/from DataBuffer.See
830 HostAdapterStatus, TargetStatus,
831 SenseDataLength, and SenseData in that order
832 for additional status information.
833 EFI_BAD_BUFFER_SIZE - The SCSI Request Packet was executed,
834 but the entire DataBuffer could not be transferred.
835 The actual number of bytes transferred is returned
836 in TransferLength. See HostAdapterStatus,
837 TargetStatus, SenseDataLength, and SenseData in
838 that order for additional status information.
839 EFI_NOT_READY - The SCSI Request Packet could not be sent because
840 there are too many SCSI Command Packets already
841 queued.The caller may retry again later.
842 EFI_DEVICE_ERROR - A device error occurred while attempting to send
843 the SCSI Request Packet. See HostAdapterStatus,
844 TargetStatus, SenseDataLength, and SenseData in
845 that order for additional status information.
846 EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid.
847 The SCSI Request Packet was not sent, so no
848 additional status information is available.
849 EFI_UNSUPPORTED - The command described by the SCSI Request Packet
850 is not supported by the SCSI initiator(i.e., SCSI
851 Host Controller). The SCSI Request Packet was not
852 sent, so no additional status information is
854 EFI_TIMEOUT - A timeout occurred while waiting for the SCSI
855 Request Packet to execute. See HostAdapterStatus,
856 TargetStatus, SenseDataLength, and SenseData in
857 that order for additional status information.
860 SCSI_IO_DEV
*ScsiIoDevice
;
862 UINT8 Target
[TARGET_MAX_BYTES
];
863 EFI_EVENT PacketEvent
;
864 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ExtRequestPacket
;
865 SCSI_EVENT_DATA EventData
;
869 if (Packet
== NULL
) {
870 return EFI_INVALID_PARAMETER
;
873 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
874 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
876 if (ScsiIoDevice
->ExtScsiSupport
) {
877 ExtRequestPacket
= (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*) Packet
;
878 Status
= ScsiIoDevice
->ExtScsiPassThru
->PassThru (
879 ScsiIoDevice
->ExtScsiPassThru
,
887 Status
= gBS
->AllocatePool (
889 sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
),
890 (VOID
**)&WorkingBuffer
893 if (EFI_ERROR (Status
)) {
894 return EFI_DEVICE_ERROR
;
898 // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.
900 Status
= ScsiioToPassThruPacket(Packet
, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
);
901 if (EFI_ERROR(Status
)) {
902 gBS
->FreePool(WorkingBuffer
);
906 if ((ScsiIoDevice
->ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO
) && (Event
!= NULL
)) {
907 EventData
.Data1
= (VOID
*)Packet
;
908 EventData
.Data2
= Event
;
912 Status
= gBS
->CreateEvent (
919 if (EFI_ERROR(Status
)) {
920 gBS
->FreePool(WorkingBuffer
);
924 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
925 ScsiIoDevice
->ScsiPassThru
,
926 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
932 if (EFI_ERROR(Status
)) {
933 gBS
->FreePool(WorkingBuffer
);
934 gBS
->CloseEvent(PacketEvent
);
940 // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert
941 // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.
943 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
944 ScsiIoDevice
->ScsiPassThru
,
945 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
950 if (EFI_ERROR(Status
)) {
951 gBS
->FreePool(WorkingBuffer
);
955 PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
,Packet
);
957 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
958 // free WorkingBuffer.
960 gBS
->FreePool(WorkingBuffer
);
968 ScsiScanCreateDevice (
969 EFI_DRIVER_BINDING_PROTOCOL
*This
,
970 EFI_HANDLE Controller
,
971 SCSI_TARGET_ID
*TargetId
,
973 SCSI_BUS_DEVICE
*ScsiBusDev
979 Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.
983 This - Protocol instance pointer
984 Controller - Controller handle
985 Pun - The Pun of the SCSI device on the SCSI channel.
986 Lun - The Lun of the SCSI device on the SCSI channel.
987 ScsiBusDev - The pointer of SCSI_BUS_DEVICE
991 EFI_SUCCESS - Successfully to discover the device and attach ScsiIoProtocol to it.
992 EFI_OUT_OF_RESOURCES - Fail to discover the device.
997 SCSI_IO_DEV
*ScsiIoDevice
;
998 EFI_DEVICE_PATH_PROTOCOL
*ScsiDevicePath
;
1000 Status
= gBS
->AllocatePool (
1001 EfiBootServicesData
,
1002 sizeof (SCSI_IO_DEV
),
1003 (VOID
**) &ScsiIoDevice
1005 if (EFI_ERROR (Status
)) {
1009 ZeroMem (ScsiIoDevice
, sizeof (SCSI_IO_DEV
));
1011 ScsiIoDevice
->Signature
= SCSI_IO_DEV_SIGNATURE
;
1012 CopyMem(&ScsiIoDevice
->Pun
, TargetId
, TARGET_MAX_BYTES
);
1013 ScsiIoDevice
->Lun
= Lun
;
1015 if (ScsiBusDev
->ExtScsiSupport
) {
1016 ScsiIoDevice
->ExtScsiPassThru
= ScsiBusDev
->ExtScsiInterface
;
1017 ScsiIoDevice
->ExtScsiSupport
= TRUE
;
1018 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ExtScsiPassThru
->Mode
->IoAlign
;
1021 ScsiIoDevice
->ScsiPassThru
= ScsiBusDev
->ScsiInterface
;
1022 ScsiIoDevice
->ExtScsiSupport
= FALSE
;
1023 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ScsiPassThru
->Mode
->IoAlign
;
1026 ScsiIoDevice
->ScsiIo
.GetDeviceType
= ScsiGetDeviceType
;
1027 ScsiIoDevice
->ScsiIo
.GetDeviceLocation
= ScsiGetDeviceLocation
;
1028 ScsiIoDevice
->ScsiIo
.ResetBus
= ScsiResetBus
;
1029 ScsiIoDevice
->ScsiIo
.ResetDevice
= ScsiResetDevice
;
1030 ScsiIoDevice
->ScsiIo
.ExecuteScsiCommand
= ScsiExecuteSCSICommand
;
1033 if (!DiscoverScsiDevice (ScsiIoDevice
)) {
1034 gBS
->FreePool (ScsiIoDevice
);
1035 return EFI_OUT_OF_RESOURCES
;
1041 if (ScsiIoDevice
->ExtScsiSupport
){
1042 Status
= ScsiIoDevice
->ExtScsiPassThru
->BuildDevicePath (
1043 ScsiIoDevice
->ExtScsiPassThru
,
1044 &ScsiIoDevice
->Pun
.ScsiId
.ExtScsi
[0],
1048 if (Status
== EFI_OUT_OF_RESOURCES
) {
1049 gBS
->FreePool (ScsiIoDevice
);
1053 Status
= ScsiIoDevice
->ScsiPassThru
->BuildDevicePath (
1054 ScsiIoDevice
->ScsiPassThru
,
1055 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
1059 if (Status
== EFI_OUT_OF_RESOURCES
) {
1060 gBS
->FreePool (ScsiIoDevice
);
1065 ScsiIoDevice
->DevicePath
= AppendDevicePathNode (
1066 ScsiBusDev
->DevicePath
,
1070 // The memory space for ScsiDevicePath is allocated in
1071 // ScsiPassThru->BuildDevicePath() function; It is no longer used
1072 // after EfiAppendDevicePathNode,so free the memory it occupies.
1074 gBS
->FreePool (ScsiDevicePath
);
1076 if (ScsiIoDevice
->DevicePath
== NULL
) {
1077 gBS
->FreePool (ScsiIoDevice
);
1078 return EFI_OUT_OF_RESOURCES
;
1081 Status
= gBS
->InstallMultipleProtocolInterfaces (
1082 &ScsiIoDevice
->Handle
,
1083 &gEfiDevicePathProtocolGuid
,
1084 ScsiIoDevice
->DevicePath
,
1085 &gEfiScsiIoProtocolGuid
,
1086 &ScsiIoDevice
->ScsiIo
,
1089 if (EFI_ERROR (Status
)) {
1090 gBS
->FreePool (ScsiIoDevice
);
1091 return EFI_OUT_OF_RESOURCES
;
1093 if (ScsiBusDev
->ExtScsiSupport
) {
1096 &gEfiExtScsiPassThruProtocolGuid
,
1097 (VOID
**) &(ScsiBusDev
->ExtScsiInterface
),
1098 This
->DriverBindingHandle
,
1099 ScsiIoDevice
->Handle
,
1100 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1105 &gEfiScsiPassThruProtocolGuid
,
1106 (VOID
**) &(ScsiBusDev
->ScsiInterface
),
1107 This
->DriverBindingHandle
,
1108 ScsiIoDevice
->Handle
,
1109 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1118 DiscoverScsiDevice (
1119 SCSI_IO_DEV
*ScsiIoDevice
1123 Routine Description:
1125 Discovery SCSI Device
1129 ScsiIoDevice - The pointer of SCSI_IO_DEV
1133 TRUE - Find SCSI Device and verify it.
1134 FALSE - Unable to find SCSI Device.
1139 UINT32 InquiryDataLength
;
1140 UINT8 SenseDataLength
;
1141 UINT8 HostAdapterStatus
;
1143 EFI_SCSI_SENSE_DATA SenseData
;
1144 EFI_SCSI_INQUIRY_DATA InquiryData
;
1146 HostAdapterStatus
= 0;
1149 // Using Inquiry command to scan for the device
1151 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1152 SenseDataLength
= sizeof (EFI_SCSI_SENSE_DATA
);
1154 Status
= ScsiInquiryCommand (
1155 &ScsiIoDevice
->ScsiIo
,
1156 EfiScsiStallSeconds (1),
1157 (VOID
*) &SenseData
,
1161 (VOID
*) &InquiryData
,
1165 if (EFI_ERROR (Status
)) {
1167 // ParseSenseData (&SenseData,SenseDataLength);
1172 // Retrieved inquiry data successfully
1174 if ((InquiryData
.Peripheral_Qualifier
!= 0) &&
1175 (InquiryData
.Peripheral_Qualifier
!= 3)) {
1179 if (InquiryData
.Peripheral_Qualifier
== 3) {
1180 if (InquiryData
.Peripheral_Type
!= 0x1f) {
1185 if (0x1e >= InquiryData
.Peripheral_Type
&& InquiryData
.Peripheral_Type
>= 0xa) {
1190 // valid device type and peripheral qualifier combination.
1192 ScsiIoDevice
->ScsiDeviceType
= InquiryData
.Peripheral_Type
;
1193 ScsiIoDevice
->RemovableDevice
= InquiryData
.RMB
;
1194 if (InquiryData
.Version
== 0) {
1195 ScsiIoDevice
->ScsiVersion
= 0;
1198 // ANSI-approved version
1200 ScsiIoDevice
->ScsiVersion
= (UINT8
) (InquiryData
.Version
& 0x03);
1210 ScsiioToPassThruPacket (
1211 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
1212 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
1216 Routine Description:
1218 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to
1219 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet
1223 Packet - The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1224 CommandPacket - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1233 //EFI 1.10 doesn't support Bi-Direction Command.
1235 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL
) {
1236 return EFI_UNSUPPORTED
;
1239 ZeroMem (CommandPacket
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1241 CommandPacket
->Timeout
= Packet
->Timeout
;
1242 CommandPacket
->Cdb
= Packet
->Cdb
;
1243 CommandPacket
->CdbLength
= Packet
->CdbLength
;
1244 CommandPacket
->DataDirection
= Packet
->DataDirection
;
1245 CommandPacket
->HostAdapterStatus
= Packet
->HostAdapterStatus
;
1246 CommandPacket
->TargetStatus
= Packet
->TargetStatus
;
1247 CommandPacket
->SenseData
= Packet
->SenseData
;
1248 CommandPacket
->SenseDataLength
= Packet
->SenseDataLength
;
1250 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1251 CommandPacket
->DataBuffer
= Packet
->InDataBuffer
;
1252 CommandPacket
->TransferLength
= Packet
->InTransferLength
;
1253 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1254 CommandPacket
->DataBuffer
= Packet
->OutDataBuffer
;
1255 CommandPacket
->TransferLength
= Packet
->OutTransferLength
;
1264 PassThruToScsiioPacket (
1265 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
1266 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
1270 Routine Description:
1272 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to
1273 EFI_SCSI_IO_SCSI_REQUEST_PACKET packet
1277 ScsiPacket - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1278 Packet - The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1286 Packet
->Timeout
= ScsiPacket
->Timeout
;
1287 Packet
->Cdb
= ScsiPacket
->Cdb
;
1288 Packet
->CdbLength
= ScsiPacket
->CdbLength
;
1289 Packet
->DataDirection
= ScsiPacket
->DataDirection
;
1290 Packet
->HostAdapterStatus
= ScsiPacket
->HostAdapterStatus
;
1291 Packet
->TargetStatus
= ScsiPacket
->TargetStatus
;
1292 Packet
->SenseData
= ScsiPacket
->SenseData
;
1293 Packet
->SenseDataLength
= ScsiPacket
->SenseDataLength
;
1295 if (ScsiPacket
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1296 Packet
->InDataBuffer
= ScsiPacket
->DataBuffer
;
1297 Packet
->InTransferLength
= ScsiPacket
->TransferLength
;
1298 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1299 Packet
->OutDataBuffer
= ScsiPacket
->DataBuffer
;
1300 Packet
->OutTransferLength
= ScsiPacket
->TransferLength
;
1317 Routine Description:
1319 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
1324 Event - The instance of EFI_EVENT.
1325 Context - The parameter passed in.
1333 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
;
1334 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
;
1335 EFI_EVENT CallerEvent
;
1336 SCSI_EVENT_DATA
*PassData
;
1338 PassData
= (SCSI_EVENT_DATA
*)Context
;
1339 Packet
= (EFI_SCSI_IO_SCSI_REQUEST_PACKET
*)PassData
->Data1
;
1340 ScsiPacket
= (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
;
1343 // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.
1345 PassThruToScsiioPacket(ScsiPacket
, Packet
);
1348 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1349 // free WorkingBuffer.
1351 gBS
->FreePool(WorkingBuffer
);
1354 // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.
1356 CallerEvent
= PassData
->Data2
;
1357 gBS
->CloseEvent(Event
);
1358 gBS
->SignalEvent(CallerEvent
);