3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
26 #include <Protocol/ScsiPassThru.h>
27 #include <Protocol/ScsiPassThruExt.h>
28 #include <Protocol/ScsiIo.h>
29 #include <Protocol/ComponentName.h>
30 #include <Protocol/DriverBinding.h>
31 #include <Protocol/DevicePath.h>
33 #include <Library/DebugLib.h>
34 #include <Library/UefiDriverEntryPoint.h>
35 #include <Library/UefiLib.h>
36 #include <Library/BaseMemoryLib.h>
37 #include <Library/MemoryAllocationLib.h>
38 #include <Library/ScsiLib.h>
39 #include <Library/UefiBootServicesTableLib.h>
40 #include <Library/DevicePathLib.h>
44 EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding
= {
45 SCSIBusDriverBindingSupported
,
46 SCSIBusDriverBindingStart
,
47 SCSIBusDriverBindingStop
,
55 // The ScsiBusProtocol is just used to locate ScsiBusDev
56 // structure in the SCSIBusDriverBindingStop(). Then we can
57 // Close all opened protocols and release this structure.
59 STATIC EFI_GUID mScsiBusProtocolGuid
= EFI_SCSI_BUS_PROTOCOL_GUID
;
61 STATIC VOID
*WorkingBuffer
;
66 ScsiioToPassThruPacket (
67 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
68 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
76 PassThruToScsiioPacket (
77 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
78 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
91 The user Entry Point for module ScsiBus. The user code starts with this function.
93 @param[in] ImageHandle The firmware allocated handle for the EFI image.
94 @param[in] SystemTable A pointer to the EFI System Table.
96 @retval EFI_SUCCESS The entry point is executed successfully.
97 @retval other Some error occurs when executing this entry point.
103 IN EFI_HANDLE ImageHandle
,
104 IN EFI_SYSTEM_TABLE
*SystemTable
110 // Install driver model protocol(s).
112 Status
= EfiLibInstallAllDriverProtocols (
115 &gSCSIBusDriverBinding
,
117 &gScsiBusComponentName
,
121 ASSERT_EFI_ERROR (Status
);
128 SCSIBusDriverBindingSupported (
129 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
130 IN EFI_HANDLE Controller
,
131 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
137 Test to see if this driver supports ControllerHandle. Any ControllerHandle
138 that has ExtScsiPassThruProtocol/ScsiPassThruProtocol installed will be supported.
142 This - Protocol instance pointer.
143 Controller - Handle of device to test
144 RemainingDevicePath - Not used
148 EFI_SUCCESS - This driver supports this device.
149 EFI_UNSUPPORTED - This driver does not support this device.
155 EFI_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
156 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtPassThru
;
158 // Check for the existence of Extended SCSI Pass Thru Protocol and SCSI Pass Thru Protocol
160 Status
= gBS
->OpenProtocol (
162 &gEfiExtScsiPassThruProtocolGuid
,
163 (VOID
**)&ExtPassThru
,
164 This
->DriverBindingHandle
,
166 EFI_OPEN_PROTOCOL_BY_DRIVER
169 if (Status
== EFI_ALREADY_STARTED
) {
173 if (EFI_ERROR (Status
)) {
174 Status
= gBS
->OpenProtocol (
176 &gEfiScsiPassThruProtocolGuid
,
178 This
->DriverBindingHandle
,
180 EFI_OPEN_PROTOCOL_BY_DRIVER
183 if (Status
== EFI_ALREADY_STARTED
) {
187 if (EFI_ERROR (Status
)) {
193 &gEfiScsiPassThruProtocolGuid
,
194 This
->DriverBindingHandle
,
202 &gEfiExtScsiPassThruProtocolGuid
,
203 This
->DriverBindingHandle
,
212 SCSIBusDriverBindingStart (
213 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
214 IN EFI_HANDLE Controller
,
215 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
220 Starting the SCSI Bus Driver
223 This - Protocol instance pointer.
224 Controller - Handle of device to test
225 RemainingDevicePath - Not used
228 EFI_SUCCESS - This driver supports this device.
229 EFI_UNSUPPORTED - This driver does not support this device.
230 EFI_DEVICE_ERROR - This driver cannot be started due to device Error
236 BOOLEAN ScanOtherPuns
;
237 BOOLEAN FromFirstTarget
;
238 BOOLEAN ExtScsiSupport
;
240 EFI_STATUS DevicePathStatus
;
241 EFI_STATUS PassThruStatus
;
242 SCSI_BUS_DEVICE
*ScsiBusDev
;
243 SCSI_TARGET_ID
*ScsiTargetId
;
244 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
245 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiInterface
;
246 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiInterface
;
247 EFI_SCSI_BUS_PROTOCOL
*BusIdentify
;
251 ScanOtherPuns
= TRUE
;
252 FromFirstTarget
= FALSE
;
253 ExtScsiSupport
= FALSE
;
254 PassThruStatus
= EFI_SUCCESS
;
256 ScsiTargetId
= AllocateZeroPool(sizeof(SCSI_TARGET_ID
));
257 if (ScsiTargetId
== NULL
) {
258 return EFI_OUT_OF_RESOURCES
;
261 TargetId
= &ScsiTargetId
->ScsiId
.ExtScsi
[0];
263 DevicePathStatus
= gBS
->OpenProtocol (
265 &gEfiDevicePathProtocolGuid
,
266 (VOID
**) &ParentDevicePath
,
267 This
->DriverBindingHandle
,
269 EFI_OPEN_PROTOCOL_BY_DRIVER
271 if (EFI_ERROR (DevicePathStatus
) && (DevicePathStatus
!= EFI_ALREADY_STARTED
)) {
272 return DevicePathStatus
;
276 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
277 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
278 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
280 Status
= gBS
->OpenProtocol (
282 &gEfiExtScsiPassThruProtocolGuid
,
283 (VOID
**) &ExtScsiInterface
,
284 This
->DriverBindingHandle
,
286 EFI_OPEN_PROTOCOL_BY_DRIVER
289 // Fail to open UEFI ExtendPassThru Protocol, then try to open EFI PassThru Protocol instead.
291 if (EFI_ERROR(Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
292 Status
= gBS
->OpenProtocol (
294 &gEfiScsiPassThruProtocolGuid
,
295 (VOID
**) &ScsiInterface
,
296 This
->DriverBindingHandle
,
298 EFI_OPEN_PROTOCOL_BY_DRIVER
301 // Fail to open EFI PassThru Protocol, Close the DevicePathProtocol if it is opened by this time.
303 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
304 if (!EFI_ERROR(DevicePathStatus
)) {
307 &gEfiDevicePathProtocolGuid
,
308 This
->DriverBindingHandle
,
316 // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol
317 // with BY_DRIVER if it is also present on the handle. The intent is to prevent
318 // another SCSI Bus Driver to work on the same host handle.
320 ExtScsiSupport
= TRUE
;
321 PassThruStatus
= gBS
->OpenProtocol (
323 &gEfiScsiPassThruProtocolGuid
,
324 (VOID
**) &ScsiInterface
,
325 This
->DriverBindingHandle
,
327 EFI_OPEN_PROTOCOL_BY_DRIVER
331 if (Status
!= EFI_ALREADY_STARTED
) {
333 // Go through here means either ExtPassThru or PassThru Protocol is successfully opened
334 // on this handle for this time. Then construct Host controller private data.
337 ScsiBusDev
= AllocateZeroPool(sizeof(SCSI_BUS_DEVICE
));
338 if (ScsiBusDev
== NULL
) {
339 Status
= EFI_OUT_OF_RESOURCES
;
342 ScsiBusDev
->Signature
= SCSI_BUS_DEVICE_SIGNATURE
;
343 ScsiBusDev
->ExtScsiSupport
= ExtScsiSupport
;
344 ScsiBusDev
->DevicePath
= ParentDevicePath
;
345 if (ScsiBusDev
->ExtScsiSupport
) {
346 ScsiBusDev
->ExtScsiInterface
= ExtScsiInterface
;
348 ScsiBusDev
->ScsiInterface
= ScsiInterface
;
352 // Install EFI_SCSI_BUS_PROTOCOL to the controller handle, So ScsiBusDev could be
353 // retrieved on this controller handle. With ScsiBusDev, we can know which PassThru
354 // Protocol is present on the handle, UEFI ExtPassThru Protocol or EFI PassThru Protocol.
356 Status
= gBS
->InstallProtocolInterface (
358 &mScsiBusProtocolGuid
,
359 EFI_NATIVE_INTERFACE
,
360 &ScsiBusDev
->BusIdentify
362 if (EFI_ERROR (Status
)) {
367 // Go through here means Start() is re-invoked again, nothing special is required to do except
368 // picking up Host controller private information.
370 Status
= gBS
->OpenProtocol (
372 &mScsiBusProtocolGuid
,
373 (VOID
**) &BusIdentify
,
374 This
->DriverBindingHandle
,
376 EFI_OPEN_PROTOCOL_GET_PROTOCOL
379 if (EFI_ERROR (Status
)) {
382 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify
);
385 if (RemainingDevicePath
== NULL
) {
386 SetMem (ScsiTargetId
, TARGET_MAX_BYTES
,0xFF);
388 FromFirstTarget
= TRUE
;
390 if (ScsiBusDev
->ExtScsiSupport
) {
391 ScsiBusDev
->ExtScsiInterface
->GetTargetLun (ScsiBusDev
->ExtScsiInterface
, RemainingDevicePath
, &TargetId
, &Lun
);
393 ScsiBusDev
->ScsiInterface
->GetTargetLun (ScsiBusDev
->ScsiInterface
, RemainingDevicePath
, &ScsiTargetId
->ScsiId
.Scsi
, &Lun
);
397 while(ScanOtherPuns
) {
398 if (FromFirstTarget
) {
400 // Remaining Device Path is NULL, scan all the possible Puns in the
403 if (ScsiBusDev
->ExtScsiSupport
) {
404 Status
= ScsiBusDev
->ExtScsiInterface
->GetNextTargetLun (ScsiBusDev
->ExtScsiInterface
, &TargetId
, &Lun
);
406 Status
= ScsiBusDev
->ScsiInterface
->GetNextDevice (ScsiBusDev
->ScsiInterface
, &ScsiTargetId
->ScsiId
.Scsi
, &Lun
);
408 if (EFI_ERROR (Status
)) {
410 // no legal Pun and Lun found any more
415 ScanOtherPuns
= FALSE
;
418 // Avoid creating handle for the host adapter.
420 if (ScsiBusDev
->ExtScsiSupport
) {
421 if ((ScsiTargetId
->ScsiId
.Scsi
) == ScsiBusDev
->ExtScsiInterface
->Mode
->AdapterId
) {
425 if ((ScsiTargetId
->ScsiId
.Scsi
) == ScsiBusDev
->ScsiInterface
->Mode
->AdapterId
) {
430 // Scan for the scsi device, if it attaches to the scsi bus,
431 // then create handle and install scsi i/o protocol.
433 Status
= ScsiScanCreateDevice (This
, Controller
, ScsiTargetId
, Lun
, ScsiBusDev
);
435 gBS
->FreePool (ScsiTargetId
);
440 if (ScsiBusDev
!= NULL
) {
441 gBS
->FreePool (ScsiBusDev
);
444 if (ExtScsiSupport
) {
447 &gEfiExtScsiPassThruProtocolGuid
,
448 This
->DriverBindingHandle
,
451 if (!EFI_ERROR (PassThruStatus
)) {
454 &gEfiScsiPassThruProtocolGuid
,
455 This
->DriverBindingHandle
,
462 &gEfiScsiPassThruProtocolGuid
,
463 This
->DriverBindingHandle
,
472 SCSIBusDriverBindingStop (
473 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
474 IN EFI_HANDLE Controller
,
475 IN UINTN NumberOfChildren
,
476 IN EFI_HANDLE
*ChildHandleBuffer
482 Stop this driver on ControllerHandle. Support stoping any child handles
483 created by this driver.
487 This - Protocol instance pointer.
488 Controller - Handle of device to stop driver on
489 NumberOfChildren - Number of Children in the ChildHandleBuffer
490 ChildHandleBuffer - List of handles for the children we need to stop.
499 BOOLEAN AllChildrenStopped
;
501 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
502 SCSI_IO_DEV
*ScsiIoDevice
;
504 EFI_SCSI_BUS_PROTOCOL
*Scsidentifier
;
505 SCSI_BUS_DEVICE
*ScsiBusDev
;
507 if (NumberOfChildren
== 0) {
509 // Get the SCSI_BUS_DEVICE
511 Status
= gBS
->OpenProtocol (
513 &mScsiBusProtocolGuid
,
514 (VOID
**) &Scsidentifier
,
515 This
->DriverBindingHandle
,
517 EFI_OPEN_PROTOCOL_GET_PROTOCOL
520 if (EFI_ERROR (Status
)) {
521 return EFI_DEVICE_ERROR
;
524 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier
);
527 // Uninstall SCSI Bus Protocol
529 gBS
->UninstallProtocolInterface (
531 &mScsiBusProtocolGuid
,
532 &ScsiBusDev
->BusIdentify
536 // Close the bus driver
538 if (ScsiBusDev
->ExtScsiSupport
) {
541 &gEfiExtScsiPassThruProtocolGuid
,
542 This
->DriverBindingHandle
,
548 &gEfiScsiPassThruProtocolGuid
,
549 This
->DriverBindingHandle
,
556 &gEfiDevicePathProtocolGuid
,
557 This
->DriverBindingHandle
,
560 gBS
->FreePool (ScsiBusDev
);
564 AllChildrenStopped
= TRUE
;
566 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
568 Status
= gBS
->OpenProtocol (
569 ChildHandleBuffer
[Index
],
570 &gEfiScsiIoProtocolGuid
,
572 This
->DriverBindingHandle
,
574 EFI_OPEN_PROTOCOL_GET_PROTOCOL
576 if (EFI_ERROR (Status
)) {
577 AllChildrenStopped
= FALSE
;
581 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (ScsiIo
);
583 // Close the child handle
585 if (ScsiIoDevice
->ExtScsiSupport
) {
586 Status
= gBS
->CloseProtocol (
588 &gEfiExtScsiPassThruProtocolGuid
,
589 This
->DriverBindingHandle
,
590 ChildHandleBuffer
[Index
]
594 Status
= gBS
->CloseProtocol (
596 &gEfiScsiPassThruProtocolGuid
,
597 This
->DriverBindingHandle
,
598 ChildHandleBuffer
[Index
]
602 Status
= gBS
->UninstallMultipleProtocolInterfaces (
603 ChildHandleBuffer
[Index
],
604 &gEfiDevicePathProtocolGuid
,
605 ScsiIoDevice
->DevicePath
,
606 &gEfiScsiIoProtocolGuid
,
607 &ScsiIoDevice
->ScsiIo
,
610 if (EFI_ERROR (Status
)) {
611 AllChildrenStopped
= FALSE
;
612 if (ScsiIoDevice
->ExtScsiSupport
) {
615 &gEfiExtScsiPassThruProtocolGuid
,
617 This
->DriverBindingHandle
,
618 ChildHandleBuffer
[Index
],
619 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
624 &gEfiScsiPassThruProtocolGuid
,
626 This
->DriverBindingHandle
,
627 ChildHandleBuffer
[Index
],
628 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
632 gBS
->FreePool (ScsiIoDevice
);
636 if (!AllChildrenStopped
) {
637 return EFI_DEVICE_ERROR
;
646 IN EFI_SCSI_IO_PROTOCOL
*This
,
647 OUT UINT8
*DeviceType
653 Retrieves the device type information of the SCSI Controller.
657 This - Protocol instance pointer.
658 DeviceType - A pointer to the device type information
659 retrieved from the SCSI Controller.
663 EFI_SUCCESS - Retrieves the device type information successfully.
664 EFI_INVALID_PARAMETER - The DeviceType is NULL.
668 SCSI_IO_DEV
*ScsiIoDevice
;
670 if (DeviceType
== NULL
) {
671 return EFI_INVALID_PARAMETER
;
674 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
675 *DeviceType
= ScsiIoDevice
->ScsiDeviceType
;
681 ScsiGetDeviceLocation (
682 IN EFI_SCSI_IO_PROTOCOL
*This
,
683 IN OUT UINT8
**Target
,
690 Retrieves the device location in the SCSI channel.
694 This - Protocol instance pointer.
695 Target - A pointer to the Target Array which represents ID of a SCSI device
697 Lun - A pointer to the LUN of the SCSI device on
702 EFI_SUCCESS - Retrieves the device location successfully.
703 EFI_INVALID_PARAMETER - The Target or Lun is NULL.
707 SCSI_IO_DEV
*ScsiIoDevice
;
709 if (Target
== NULL
|| Lun
== NULL
) {
710 return EFI_INVALID_PARAMETER
;
713 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
715 CopyMem (*Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
717 *Lun
= ScsiIoDevice
->Lun
;
725 IN EFI_SCSI_IO_PROTOCOL
*This
731 Resets the SCSI Bus that the SCSI Controller is attached to.
735 This - Protocol instance pointer.
739 EFI_SUCCESS - The SCSI bus is reset successfully.
740 EFI_DEVICE_ERROR - Errors encountered when resetting the SCSI bus.
741 EFI_UNSUPPORTED - The bus reset operation is not supported by the
742 SCSI Host Controller.
743 EFI_TIMEOUT - A timeout occurred while attempting to reset
747 SCSI_IO_DEV
*ScsiIoDevice
;
749 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
751 if (ScsiIoDevice
->ExtScsiSupport
){
752 return ScsiIoDevice
->ExtScsiPassThru
->ResetChannel (ScsiIoDevice
->ExtScsiPassThru
);
754 return ScsiIoDevice
->ScsiPassThru
->ResetChannel (ScsiIoDevice
->ScsiPassThru
);
761 IN EFI_SCSI_IO_PROTOCOL
*This
767 Resets the SCSI Controller that the device handle specifies.
771 This - Protocol instance pointer.
775 EFI_SUCCESS - Reset the SCSI controller successfully.
776 EFI_DEVICE_ERROR - Errors are encountered when resetting the
778 EFI_UNSUPPORTED - The SCSI bus does not support a device
780 EFI_TIMEOUT - A timeout occurred while attempting to
781 reset the SCSI Controller.
784 SCSI_IO_DEV
*ScsiIoDevice
;
785 UINT8 Target
[TARGET_MAX_BYTES
];
787 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
788 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
791 if (ScsiIoDevice
->ExtScsiSupport
) {
792 return ScsiIoDevice
->ExtScsiPassThru
->ResetTargetLun (
793 ScsiIoDevice
->ExtScsiPassThru
,
798 return ScsiIoDevice
->ScsiPassThru
->ResetTarget (
799 ScsiIoDevice
->ScsiPassThru
,
800 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
808 ScsiExecuteSCSICommand (
809 IN EFI_SCSI_IO_PROTOCOL
*This
,
810 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
811 IN EFI_EVENT Event OPTIONAL
817 Sends a SCSI Request Packet to the SCSI Controller for execution.
821 This - Protocol instance pointer.
822 Packet - The SCSI request packet to send to the SCSI
823 Controller specified by the device handle.
824 Event - If the SCSI bus where the SCSI device is attached
825 does not support non-blocking I/O, then Event is
826 ignored, and blocking I/O is performed.
827 If Event is NULL, then blocking I/O is performed.
828 If Event is not NULL and non-blocking I/O is
829 supported, then non-blocking I/O is performed,
830 and Event will be signaled when the SCSI Request
834 EFI_SUCCESS - The SCSI Request Packet was sent by the host
835 successfully, and TransferLength bytes were
836 transferred to/from DataBuffer.See
837 HostAdapterStatus, TargetStatus,
838 SenseDataLength, and SenseData in that order
839 for additional status information.
840 EFI_BAD_BUFFER_SIZE - The SCSI Request Packet was executed,
841 but the entire DataBuffer could not be transferred.
842 The actual number of bytes transferred is returned
843 in TransferLength. See HostAdapterStatus,
844 TargetStatus, SenseDataLength, and SenseData in
845 that order for additional status information.
846 EFI_NOT_READY - The SCSI Request Packet could not be sent because
847 there are too many SCSI Command Packets already
848 queued.The caller may retry again later.
849 EFI_DEVICE_ERROR - A device error occurred while attempting to send
850 the SCSI Request Packet. See HostAdapterStatus,
851 TargetStatus, SenseDataLength, and SenseData in
852 that order for additional status information.
853 EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid.
854 The SCSI Request Packet was not sent, so no
855 additional status information is available.
856 EFI_UNSUPPORTED - The command described by the SCSI Request Packet
857 is not supported by the SCSI initiator(i.e., SCSI
858 Host Controller). The SCSI Request Packet was not
859 sent, so no additional status information is
861 EFI_TIMEOUT - A timeout occurred while waiting for the SCSI
862 Request Packet to execute. See HostAdapterStatus,
863 TargetStatus, SenseDataLength, and SenseData in
864 that order for additional status information.
867 SCSI_IO_DEV
*ScsiIoDevice
;
869 UINT8 Target
[TARGET_MAX_BYTES
];
870 EFI_EVENT PacketEvent
;
871 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ExtRequestPacket
;
872 SCSI_EVENT_DATA EventData
;
876 if (Packet
== NULL
) {
877 return EFI_INVALID_PARAMETER
;
880 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
881 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
883 if (ScsiIoDevice
->ExtScsiSupport
) {
884 ExtRequestPacket
= (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*) Packet
;
885 Status
= ScsiIoDevice
->ExtScsiPassThru
->PassThru (
886 ScsiIoDevice
->ExtScsiPassThru
,
894 Status
= gBS
->AllocatePool (
896 sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
),
897 (VOID
**)&WorkingBuffer
900 if (EFI_ERROR (Status
)) {
901 return EFI_DEVICE_ERROR
;
905 // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.
907 Status
= ScsiioToPassThruPacket(Packet
, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
);
908 if (EFI_ERROR(Status
)) {
909 gBS
->FreePool(WorkingBuffer
);
913 if ((ScsiIoDevice
->ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO
) && (Event
!= NULL
)) {
914 EventData
.Data1
= (VOID
*)Packet
;
915 EventData
.Data2
= Event
;
919 Status
= gBS
->CreateEvent (
926 if (EFI_ERROR(Status
)) {
927 gBS
->FreePool(WorkingBuffer
);
931 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
932 ScsiIoDevice
->ScsiPassThru
,
933 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
939 if (EFI_ERROR(Status
)) {
940 gBS
->FreePool(WorkingBuffer
);
941 gBS
->CloseEvent(PacketEvent
);
947 // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert
948 // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.
950 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
951 ScsiIoDevice
->ScsiPassThru
,
952 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
957 if (EFI_ERROR(Status
)) {
958 gBS
->FreePool(WorkingBuffer
);
962 PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
,Packet
);
964 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
965 // free WorkingBuffer.
967 gBS
->FreePool(WorkingBuffer
);
975 ScsiScanCreateDevice (
976 EFI_DRIVER_BINDING_PROTOCOL
*This
,
977 EFI_HANDLE Controller
,
978 SCSI_TARGET_ID
*TargetId
,
980 SCSI_BUS_DEVICE
*ScsiBusDev
986 Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.
990 This - Protocol instance pointer
991 Controller - Controller handle
992 Pun - The Pun of the SCSI device on the SCSI channel.
993 Lun - The Lun of the SCSI device on the SCSI channel.
994 ScsiBusDev - The pointer of SCSI_BUS_DEVICE
998 EFI_SUCCESS - Successfully to discover the device and attach ScsiIoProtocol to it.
999 EFI_OUT_OF_RESOURCES - Fail to discover the device.
1004 SCSI_IO_DEV
*ScsiIoDevice
;
1005 EFI_DEVICE_PATH_PROTOCOL
*ScsiDevicePath
;
1007 Status
= gBS
->AllocatePool (
1008 EfiBootServicesData
,
1009 sizeof (SCSI_IO_DEV
),
1010 (VOID
**) &ScsiIoDevice
1012 if (EFI_ERROR (Status
)) {
1016 ZeroMem (ScsiIoDevice
, sizeof (SCSI_IO_DEV
));
1018 ScsiIoDevice
->Signature
= SCSI_IO_DEV_SIGNATURE
;
1019 CopyMem(&ScsiIoDevice
->Pun
, TargetId
, TARGET_MAX_BYTES
);
1020 ScsiIoDevice
->Lun
= Lun
;
1022 if (ScsiBusDev
->ExtScsiSupport
) {
1023 ScsiIoDevice
->ExtScsiPassThru
= ScsiBusDev
->ExtScsiInterface
;
1024 ScsiIoDevice
->ExtScsiSupport
= TRUE
;
1025 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ExtScsiPassThru
->Mode
->IoAlign
;
1028 ScsiIoDevice
->ScsiPassThru
= ScsiBusDev
->ScsiInterface
;
1029 ScsiIoDevice
->ExtScsiSupport
= FALSE
;
1030 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ScsiPassThru
->Mode
->IoAlign
;
1033 ScsiIoDevice
->ScsiIo
.GetDeviceType
= ScsiGetDeviceType
;
1034 ScsiIoDevice
->ScsiIo
.GetDeviceLocation
= ScsiGetDeviceLocation
;
1035 ScsiIoDevice
->ScsiIo
.ResetBus
= ScsiResetBus
;
1036 ScsiIoDevice
->ScsiIo
.ResetDevice
= ScsiResetDevice
;
1037 ScsiIoDevice
->ScsiIo
.ExecuteScsiCommand
= ScsiExecuteSCSICommand
;
1040 if (!DiscoverScsiDevice (ScsiIoDevice
)) {
1041 gBS
->FreePool (ScsiIoDevice
);
1042 return EFI_OUT_OF_RESOURCES
;
1048 if (ScsiIoDevice
->ExtScsiSupport
){
1049 Status
= ScsiIoDevice
->ExtScsiPassThru
->BuildDevicePath (
1050 ScsiIoDevice
->ExtScsiPassThru
,
1051 &ScsiIoDevice
->Pun
.ScsiId
.ExtScsi
[0],
1055 if (Status
== EFI_OUT_OF_RESOURCES
) {
1056 gBS
->FreePool (ScsiIoDevice
);
1060 Status
= ScsiIoDevice
->ScsiPassThru
->BuildDevicePath (
1061 ScsiIoDevice
->ScsiPassThru
,
1062 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
1066 if (Status
== EFI_OUT_OF_RESOURCES
) {
1067 gBS
->FreePool (ScsiIoDevice
);
1072 ScsiIoDevice
->DevicePath
= AppendDevicePathNode (
1073 ScsiBusDev
->DevicePath
,
1077 // The memory space for ScsiDevicePath is allocated in
1078 // ScsiPassThru->BuildDevicePath() function; It is no longer used
1079 // after EfiAppendDevicePathNode,so free the memory it occupies.
1081 gBS
->FreePool (ScsiDevicePath
);
1083 if (ScsiIoDevice
->DevicePath
== NULL
) {
1084 gBS
->FreePool (ScsiIoDevice
);
1085 return EFI_OUT_OF_RESOURCES
;
1088 Status
= gBS
->InstallMultipleProtocolInterfaces (
1089 &ScsiIoDevice
->Handle
,
1090 &gEfiDevicePathProtocolGuid
,
1091 ScsiIoDevice
->DevicePath
,
1092 &gEfiScsiIoProtocolGuid
,
1093 &ScsiIoDevice
->ScsiIo
,
1096 if (EFI_ERROR (Status
)) {
1097 gBS
->FreePool (ScsiIoDevice
);
1098 return EFI_OUT_OF_RESOURCES
;
1100 if (ScsiBusDev
->ExtScsiSupport
) {
1103 &gEfiExtScsiPassThruProtocolGuid
,
1104 (VOID
**) &(ScsiBusDev
->ExtScsiInterface
),
1105 This
->DriverBindingHandle
,
1106 ScsiIoDevice
->Handle
,
1107 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1112 &gEfiScsiPassThruProtocolGuid
,
1113 (VOID
**) &(ScsiBusDev
->ScsiInterface
),
1114 This
->DriverBindingHandle
,
1115 ScsiIoDevice
->Handle
,
1116 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1125 DiscoverScsiDevice (
1126 SCSI_IO_DEV
*ScsiIoDevice
1130 Routine Description:
1132 Discovery SCSI Device
1136 ScsiIoDevice - The pointer of SCSI_IO_DEV
1140 TRUE - Find SCSI Device and verify it.
1141 FALSE - Unable to find SCSI Device.
1146 UINT32 InquiryDataLength
;
1147 UINT8 SenseDataLength
;
1148 UINT8 HostAdapterStatus
;
1150 EFI_SCSI_SENSE_DATA SenseData
;
1151 EFI_SCSI_INQUIRY_DATA InquiryData
;
1153 HostAdapterStatus
= 0;
1156 // Using Inquiry command to scan for the device
1158 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1159 SenseDataLength
= sizeof (EFI_SCSI_SENSE_DATA
);
1161 Status
= ScsiInquiryCommand (
1162 &ScsiIoDevice
->ScsiIo
,
1163 EfiScsiStallSeconds (1),
1164 (VOID
*) &SenseData
,
1168 (VOID
*) &InquiryData
,
1172 if (EFI_ERROR (Status
)) {
1174 // ParseSenseData (&SenseData,SenseDataLength);
1179 // Retrieved inquiry data successfully
1181 if ((InquiryData
.Peripheral_Qualifier
!= 0) &&
1182 (InquiryData
.Peripheral_Qualifier
!= 3)) {
1186 if (InquiryData
.Peripheral_Qualifier
== 3) {
1187 if (InquiryData
.Peripheral_Type
!= 0x1f) {
1192 if (0x1e >= InquiryData
.Peripheral_Type
>= 0xa) {
1197 // valid device type and peripheral qualifier combination.
1199 ScsiIoDevice
->ScsiDeviceType
= InquiryData
.Peripheral_Type
;
1200 ScsiIoDevice
->RemovableDevice
= InquiryData
.RMB
;
1201 if (InquiryData
.Version
== 0) {
1202 ScsiIoDevice
->ScsiVersion
= 0;
1205 // ANSI-approved version
1207 ScsiIoDevice
->ScsiVersion
= (UINT8
) (InquiryData
.Version
& 0x03);
1217 ScsiioToPassThruPacket (
1218 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
1219 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
1223 Routine Description:
1225 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to
1226 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet
1230 Packet - The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1231 CommandPacket - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1240 //EFI 1.10 doesn't support Bi-Direction Command.
1242 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL
) {
1243 return EFI_UNSUPPORTED
;
1246 ZeroMem (CommandPacket
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1248 CommandPacket
->Timeout
= Packet
->Timeout
;
1249 CommandPacket
->Cdb
= Packet
->Cdb
;
1250 CommandPacket
->CdbLength
= Packet
->CdbLength
;
1251 CommandPacket
->DataDirection
= Packet
->DataDirection
;
1252 CommandPacket
->HostAdapterStatus
= Packet
->HostAdapterStatus
;
1253 CommandPacket
->TargetStatus
= Packet
->TargetStatus
;
1254 CommandPacket
->SenseData
= Packet
->SenseData
;
1255 CommandPacket
->SenseDataLength
= Packet
->SenseDataLength
;
1257 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1258 CommandPacket
->DataBuffer
= Packet
->InDataBuffer
;
1259 CommandPacket
->TransferLength
= Packet
->InTransferLength
;
1260 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1261 CommandPacket
->DataBuffer
= Packet
->OutDataBuffer
;
1262 CommandPacket
->TransferLength
= Packet
->OutTransferLength
;
1271 PassThruToScsiioPacket (
1272 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
1273 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
1277 Routine Description:
1279 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to
1280 EFI_SCSI_IO_SCSI_REQUEST_PACKET packet
1284 ScsiPacket - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1285 Packet - The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1293 Packet
->Timeout
= ScsiPacket
->Timeout
;
1294 Packet
->Cdb
= ScsiPacket
->Cdb
;
1295 Packet
->CdbLength
= ScsiPacket
->CdbLength
;
1296 Packet
->DataDirection
= ScsiPacket
->DataDirection
;
1297 Packet
->HostAdapterStatus
= ScsiPacket
->HostAdapterStatus
;
1298 Packet
->TargetStatus
= ScsiPacket
->TargetStatus
;
1299 Packet
->SenseData
= ScsiPacket
->SenseData
;
1300 Packet
->SenseDataLength
= ScsiPacket
->SenseDataLength
;
1302 if (ScsiPacket
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1303 Packet
->InDataBuffer
= ScsiPacket
->DataBuffer
;
1304 Packet
->InTransferLength
= ScsiPacket
->TransferLength
;
1305 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1306 Packet
->OutDataBuffer
= ScsiPacket
->DataBuffer
;
1307 Packet
->OutTransferLength
= ScsiPacket
->TransferLength
;
1324 Routine Description:
1326 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
1331 Event - The instance of EFI_EVENT.
1332 Context - The parameter passed in.
1340 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
;
1341 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
;
1342 EFI_EVENT CallerEvent
;
1343 SCSI_EVENT_DATA
*PassData
;
1345 PassData
= (SCSI_EVENT_DATA
*)Context
;
1346 Packet
= (EFI_SCSI_IO_SCSI_REQUEST_PACKET
*)PassData
->Data1
;
1347 ScsiPacket
= (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
;
1350 // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.
1352 PassThruToScsiioPacket(ScsiPacket
, Packet
);
1355 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1356 // free WorkingBuffer.
1358 gBS
->FreePool(WorkingBuffer
);
1361 // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.
1363 CallerEvent
= PassData
->Data2
;
1364 gBS
->CloseEvent(Event
);
1365 gBS
->SignalEvent(CallerEvent
);