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
= EfiLibInstallDriverBindingComponentName2 (
115 &gSCSIBusDriverBinding
,
117 &gScsiBusComponentName
,
118 &gScsiBusComponentName2
120 ASSERT_EFI_ERROR (Status
);
127 SCSIBusDriverBindingSupported (
128 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
129 IN EFI_HANDLE Controller
,
130 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
136 Test to see if this driver supports ControllerHandle. Any ControllerHandle
137 that has ExtScsiPassThruProtocol/ScsiPassThruProtocol installed will be supported.
141 This - Protocol instance pointer.
142 Controller - Handle of device to test
143 RemainingDevicePath - Not used
147 EFI_SUCCESS - This driver supports this device.
148 EFI_UNSUPPORTED - This driver does not support this device.
154 EFI_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
155 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtPassThru
;
157 // Check for the existence of Extended SCSI Pass Thru Protocol and SCSI Pass Thru Protocol
159 Status
= gBS
->OpenProtocol (
161 &gEfiExtScsiPassThruProtocolGuid
,
162 (VOID
**)&ExtPassThru
,
163 This
->DriverBindingHandle
,
165 EFI_OPEN_PROTOCOL_BY_DRIVER
168 if (Status
== EFI_ALREADY_STARTED
) {
172 if (EFI_ERROR (Status
)) {
173 Status
= gBS
->OpenProtocol (
175 &gEfiScsiPassThruProtocolGuid
,
177 This
->DriverBindingHandle
,
179 EFI_OPEN_PROTOCOL_BY_DRIVER
182 if (Status
== EFI_ALREADY_STARTED
) {
186 if (EFI_ERROR (Status
)) {
192 &gEfiScsiPassThruProtocolGuid
,
193 This
->DriverBindingHandle
,
201 &gEfiExtScsiPassThruProtocolGuid
,
202 This
->DriverBindingHandle
,
211 SCSIBusDriverBindingStart (
212 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
213 IN EFI_HANDLE Controller
,
214 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
219 Starting the SCSI Bus Driver
222 This - Protocol instance pointer.
223 Controller - Handle of device to test
224 RemainingDevicePath - Not used
227 EFI_SUCCESS - This driver supports this device.
228 EFI_UNSUPPORTED - This driver does not support this device.
229 EFI_DEVICE_ERROR - This driver cannot be started due to device Error
235 BOOLEAN ScanOtherPuns
;
236 BOOLEAN FromFirstTarget
;
237 BOOLEAN ExtScsiSupport
;
239 EFI_STATUS DevicePathStatus
;
240 EFI_STATUS PassThruStatus
;
241 SCSI_BUS_DEVICE
*ScsiBusDev
;
242 SCSI_TARGET_ID
*ScsiTargetId
;
243 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
244 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiInterface
;
245 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiInterface
;
246 EFI_SCSI_BUS_PROTOCOL
*BusIdentify
;
250 ScanOtherPuns
= TRUE
;
251 FromFirstTarget
= FALSE
;
252 ExtScsiSupport
= FALSE
;
253 PassThruStatus
= EFI_SUCCESS
;
255 ScsiTargetId
= AllocateZeroPool(sizeof(SCSI_TARGET_ID
));
256 if (ScsiTargetId
== NULL
) {
257 return EFI_OUT_OF_RESOURCES
;
260 TargetId
= &ScsiTargetId
->ScsiId
.ExtScsi
[0];
262 DevicePathStatus
= gBS
->OpenProtocol (
264 &gEfiDevicePathProtocolGuid
,
265 (VOID
**) &ParentDevicePath
,
266 This
->DriverBindingHandle
,
268 EFI_OPEN_PROTOCOL_BY_DRIVER
270 if (EFI_ERROR (DevicePathStatus
) && (DevicePathStatus
!= EFI_ALREADY_STARTED
)) {
271 return DevicePathStatus
;
275 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
276 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
277 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
279 Status
= gBS
->OpenProtocol (
281 &gEfiExtScsiPassThruProtocolGuid
,
282 (VOID
**) &ExtScsiInterface
,
283 This
->DriverBindingHandle
,
285 EFI_OPEN_PROTOCOL_BY_DRIVER
288 // Fail to open UEFI ExtendPassThru Protocol, then try to open EFI PassThru Protocol instead.
290 if (EFI_ERROR(Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
291 Status
= gBS
->OpenProtocol (
293 &gEfiScsiPassThruProtocolGuid
,
294 (VOID
**) &ScsiInterface
,
295 This
->DriverBindingHandle
,
297 EFI_OPEN_PROTOCOL_BY_DRIVER
300 // Fail to open EFI PassThru Protocol, Close the DevicePathProtocol if it is opened by this time.
302 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
303 if (!EFI_ERROR(DevicePathStatus
)) {
306 &gEfiDevicePathProtocolGuid
,
307 This
->DriverBindingHandle
,
315 // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol
316 // with BY_DRIVER if it is also present on the handle. The intent is to prevent
317 // another SCSI Bus Driver to work on the same host handle.
319 ExtScsiSupport
= TRUE
;
320 PassThruStatus
= gBS
->OpenProtocol (
322 &gEfiScsiPassThruProtocolGuid
,
323 (VOID
**) &ScsiInterface
,
324 This
->DriverBindingHandle
,
326 EFI_OPEN_PROTOCOL_BY_DRIVER
330 if (Status
!= EFI_ALREADY_STARTED
) {
332 // Go through here means either ExtPassThru or PassThru Protocol is successfully opened
333 // on this handle for this time. Then construct Host controller private data.
336 ScsiBusDev
= AllocateZeroPool(sizeof(SCSI_BUS_DEVICE
));
337 if (ScsiBusDev
== NULL
) {
338 Status
= EFI_OUT_OF_RESOURCES
;
341 ScsiBusDev
->Signature
= SCSI_BUS_DEVICE_SIGNATURE
;
342 ScsiBusDev
->ExtScsiSupport
= ExtScsiSupport
;
343 ScsiBusDev
->DevicePath
= ParentDevicePath
;
344 if (ScsiBusDev
->ExtScsiSupport
) {
345 ScsiBusDev
->ExtScsiInterface
= ExtScsiInterface
;
347 ScsiBusDev
->ScsiInterface
= ScsiInterface
;
351 // Install EFI_SCSI_BUS_PROTOCOL to the controller handle, So ScsiBusDev could be
352 // retrieved on this controller handle. With ScsiBusDev, we can know which PassThru
353 // Protocol is present on the handle, UEFI ExtPassThru Protocol or EFI PassThru Protocol.
355 Status
= gBS
->InstallProtocolInterface (
357 &mScsiBusProtocolGuid
,
358 EFI_NATIVE_INTERFACE
,
359 &ScsiBusDev
->BusIdentify
361 if (EFI_ERROR (Status
)) {
366 // Go through here means Start() is re-invoked again, nothing special is required to do except
367 // picking up Host controller private information.
369 Status
= gBS
->OpenProtocol (
371 &mScsiBusProtocolGuid
,
372 (VOID
**) &BusIdentify
,
373 This
->DriverBindingHandle
,
375 EFI_OPEN_PROTOCOL_GET_PROTOCOL
378 if (EFI_ERROR (Status
)) {
381 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify
);
384 if (RemainingDevicePath
== NULL
) {
385 SetMem (ScsiTargetId
, TARGET_MAX_BYTES
,0xFF);
387 FromFirstTarget
= TRUE
;
389 if (ScsiBusDev
->ExtScsiSupport
) {
390 ScsiBusDev
->ExtScsiInterface
->GetTargetLun (ScsiBusDev
->ExtScsiInterface
, RemainingDevicePath
, &TargetId
, &Lun
);
392 ScsiBusDev
->ScsiInterface
->GetTargetLun (ScsiBusDev
->ScsiInterface
, RemainingDevicePath
, &ScsiTargetId
->ScsiId
.Scsi
, &Lun
);
396 while(ScanOtherPuns
) {
397 if (FromFirstTarget
) {
399 // Remaining Device Path is NULL, scan all the possible Puns in the
402 if (ScsiBusDev
->ExtScsiSupport
) {
403 Status
= ScsiBusDev
->ExtScsiInterface
->GetNextTargetLun (ScsiBusDev
->ExtScsiInterface
, &TargetId
, &Lun
);
405 Status
= ScsiBusDev
->ScsiInterface
->GetNextDevice (ScsiBusDev
->ScsiInterface
, &ScsiTargetId
->ScsiId
.Scsi
, &Lun
);
407 if (EFI_ERROR (Status
)) {
409 // no legal Pun and Lun found any more
414 ScanOtherPuns
= FALSE
;
417 // Avoid creating handle for the host adapter.
419 if (ScsiBusDev
->ExtScsiSupport
) {
420 if ((ScsiTargetId
->ScsiId
.Scsi
) == ScsiBusDev
->ExtScsiInterface
->Mode
->AdapterId
) {
424 if ((ScsiTargetId
->ScsiId
.Scsi
) == ScsiBusDev
->ScsiInterface
->Mode
->AdapterId
) {
429 // Scan for the scsi device, if it attaches to the scsi bus,
430 // then create handle and install scsi i/o protocol.
432 Status
= ScsiScanCreateDevice (This
, Controller
, ScsiTargetId
, Lun
, ScsiBusDev
);
434 gBS
->FreePool (ScsiTargetId
);
439 if (ScsiBusDev
!= NULL
) {
440 gBS
->FreePool (ScsiBusDev
);
443 if (ExtScsiSupport
) {
446 &gEfiExtScsiPassThruProtocolGuid
,
447 This
->DriverBindingHandle
,
450 if (!EFI_ERROR (PassThruStatus
)) {
453 &gEfiScsiPassThruProtocolGuid
,
454 This
->DriverBindingHandle
,
461 &gEfiScsiPassThruProtocolGuid
,
462 This
->DriverBindingHandle
,
471 SCSIBusDriverBindingStop (
472 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
473 IN EFI_HANDLE Controller
,
474 IN UINTN NumberOfChildren
,
475 IN EFI_HANDLE
*ChildHandleBuffer
481 Stop this driver on ControllerHandle. Support stoping any child handles
482 created by this driver.
486 This - Protocol instance pointer.
487 Controller - Handle of device to stop driver on
488 NumberOfChildren - Number of Children in the ChildHandleBuffer
489 ChildHandleBuffer - List of handles for the children we need to stop.
498 BOOLEAN AllChildrenStopped
;
500 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
501 SCSI_IO_DEV
*ScsiIoDevice
;
503 EFI_SCSI_BUS_PROTOCOL
*Scsidentifier
;
504 SCSI_BUS_DEVICE
*ScsiBusDev
;
506 if (NumberOfChildren
== 0) {
508 // Get the SCSI_BUS_DEVICE
510 Status
= gBS
->OpenProtocol (
512 &mScsiBusProtocolGuid
,
513 (VOID
**) &Scsidentifier
,
514 This
->DriverBindingHandle
,
516 EFI_OPEN_PROTOCOL_GET_PROTOCOL
519 if (EFI_ERROR (Status
)) {
520 return EFI_DEVICE_ERROR
;
523 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier
);
526 // Uninstall SCSI Bus Protocol
528 gBS
->UninstallProtocolInterface (
530 &mScsiBusProtocolGuid
,
531 &ScsiBusDev
->BusIdentify
535 // Close the bus driver
537 if (ScsiBusDev
->ExtScsiSupport
) {
540 &gEfiExtScsiPassThruProtocolGuid
,
541 This
->DriverBindingHandle
,
547 &gEfiScsiPassThruProtocolGuid
,
548 This
->DriverBindingHandle
,
555 &gEfiDevicePathProtocolGuid
,
556 This
->DriverBindingHandle
,
559 gBS
->FreePool (ScsiBusDev
);
563 AllChildrenStopped
= TRUE
;
565 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
567 Status
= gBS
->OpenProtocol (
568 ChildHandleBuffer
[Index
],
569 &gEfiScsiIoProtocolGuid
,
571 This
->DriverBindingHandle
,
573 EFI_OPEN_PROTOCOL_GET_PROTOCOL
575 if (EFI_ERROR (Status
)) {
576 AllChildrenStopped
= FALSE
;
580 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (ScsiIo
);
582 // Close the child handle
584 if (ScsiIoDevice
->ExtScsiSupport
) {
585 Status
= gBS
->CloseProtocol (
587 &gEfiExtScsiPassThruProtocolGuid
,
588 This
->DriverBindingHandle
,
589 ChildHandleBuffer
[Index
]
593 Status
= gBS
->CloseProtocol (
595 &gEfiScsiPassThruProtocolGuid
,
596 This
->DriverBindingHandle
,
597 ChildHandleBuffer
[Index
]
601 Status
= gBS
->UninstallMultipleProtocolInterfaces (
602 ChildHandleBuffer
[Index
],
603 &gEfiDevicePathProtocolGuid
,
604 ScsiIoDevice
->DevicePath
,
605 &gEfiScsiIoProtocolGuid
,
606 &ScsiIoDevice
->ScsiIo
,
609 if (EFI_ERROR (Status
)) {
610 AllChildrenStopped
= FALSE
;
611 if (ScsiIoDevice
->ExtScsiSupport
) {
614 &gEfiExtScsiPassThruProtocolGuid
,
616 This
->DriverBindingHandle
,
617 ChildHandleBuffer
[Index
],
618 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
623 &gEfiScsiPassThruProtocolGuid
,
625 This
->DriverBindingHandle
,
626 ChildHandleBuffer
[Index
],
627 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
631 gBS
->FreePool (ScsiIoDevice
);
635 if (!AllChildrenStopped
) {
636 return EFI_DEVICE_ERROR
;
645 IN EFI_SCSI_IO_PROTOCOL
*This
,
646 OUT UINT8
*DeviceType
652 Retrieves the device type information of the SCSI Controller.
656 This - Protocol instance pointer.
657 DeviceType - A pointer to the device type information
658 retrieved from the SCSI Controller.
662 EFI_SUCCESS - Retrieves the device type information successfully.
663 EFI_INVALID_PARAMETER - The DeviceType is NULL.
667 SCSI_IO_DEV
*ScsiIoDevice
;
669 if (DeviceType
== NULL
) {
670 return EFI_INVALID_PARAMETER
;
673 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
674 *DeviceType
= ScsiIoDevice
->ScsiDeviceType
;
680 ScsiGetDeviceLocation (
681 IN EFI_SCSI_IO_PROTOCOL
*This
,
682 IN OUT UINT8
**Target
,
689 Retrieves the device location in the SCSI channel.
693 This - Protocol instance pointer.
694 Target - A pointer to the Target Array which represents ID of a SCSI device
696 Lun - A pointer to the LUN of the SCSI device on
701 EFI_SUCCESS - Retrieves the device location successfully.
702 EFI_INVALID_PARAMETER - The Target or Lun is NULL.
706 SCSI_IO_DEV
*ScsiIoDevice
;
708 if (Target
== NULL
|| Lun
== NULL
) {
709 return EFI_INVALID_PARAMETER
;
712 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
714 CopyMem (*Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
716 *Lun
= ScsiIoDevice
->Lun
;
724 IN EFI_SCSI_IO_PROTOCOL
*This
730 Resets the SCSI Bus that the SCSI Controller is attached to.
734 This - Protocol instance pointer.
738 EFI_SUCCESS - The SCSI bus is reset successfully.
739 EFI_DEVICE_ERROR - Errors encountered when resetting the SCSI bus.
740 EFI_UNSUPPORTED - The bus reset operation is not supported by the
741 SCSI Host Controller.
742 EFI_TIMEOUT - A timeout occurred while attempting to reset
746 SCSI_IO_DEV
*ScsiIoDevice
;
748 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
750 if (ScsiIoDevice
->ExtScsiSupport
){
751 return ScsiIoDevice
->ExtScsiPassThru
->ResetChannel (ScsiIoDevice
->ExtScsiPassThru
);
753 return ScsiIoDevice
->ScsiPassThru
->ResetChannel (ScsiIoDevice
->ScsiPassThru
);
760 IN EFI_SCSI_IO_PROTOCOL
*This
766 Resets the SCSI Controller that the device handle specifies.
770 This - Protocol instance pointer.
774 EFI_SUCCESS - Reset the SCSI controller successfully.
775 EFI_DEVICE_ERROR - Errors are encountered when resetting the
777 EFI_UNSUPPORTED - The SCSI bus does not support a device
779 EFI_TIMEOUT - A timeout occurred while attempting to
780 reset the SCSI Controller.
783 SCSI_IO_DEV
*ScsiIoDevice
;
784 UINT8 Target
[TARGET_MAX_BYTES
];
786 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
787 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
790 if (ScsiIoDevice
->ExtScsiSupport
) {
791 return ScsiIoDevice
->ExtScsiPassThru
->ResetTargetLun (
792 ScsiIoDevice
->ExtScsiPassThru
,
797 return ScsiIoDevice
->ScsiPassThru
->ResetTarget (
798 ScsiIoDevice
->ScsiPassThru
,
799 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
807 ScsiExecuteSCSICommand (
808 IN EFI_SCSI_IO_PROTOCOL
*This
,
809 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
810 IN EFI_EVENT Event OPTIONAL
816 Sends a SCSI Request Packet to the SCSI Controller for execution.
820 This - Protocol instance pointer.
821 Packet - The SCSI request packet to send to the SCSI
822 Controller specified by the device handle.
823 Event - If the SCSI bus where the SCSI device is attached
824 does not support non-blocking I/O, then Event is
825 ignored, and blocking I/O is performed.
826 If Event is NULL, then blocking I/O is performed.
827 If Event is not NULL and non-blocking I/O is
828 supported, then non-blocking I/O is performed,
829 and Event will be signaled when the SCSI Request
833 EFI_SUCCESS - The SCSI Request Packet was sent by the host
834 successfully, and TransferLength bytes were
835 transferred to/from DataBuffer.See
836 HostAdapterStatus, TargetStatus,
837 SenseDataLength, and SenseData in that order
838 for additional status information.
839 EFI_BAD_BUFFER_SIZE - The SCSI Request Packet was executed,
840 but the entire DataBuffer could not be transferred.
841 The actual number of bytes transferred is returned
842 in TransferLength. See HostAdapterStatus,
843 TargetStatus, SenseDataLength, and SenseData in
844 that order for additional status information.
845 EFI_NOT_READY - The SCSI Request Packet could not be sent because
846 there are too many SCSI Command Packets already
847 queued.The caller may retry again later.
848 EFI_DEVICE_ERROR - A device error occurred while attempting to send
849 the SCSI Request Packet. See HostAdapterStatus,
850 TargetStatus, SenseDataLength, and SenseData in
851 that order for additional status information.
852 EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid.
853 The SCSI Request Packet was not sent, so no
854 additional status information is available.
855 EFI_UNSUPPORTED - The command described by the SCSI Request Packet
856 is not supported by the SCSI initiator(i.e., SCSI
857 Host Controller). The SCSI Request Packet was not
858 sent, so no additional status information is
860 EFI_TIMEOUT - A timeout occurred while waiting for the SCSI
861 Request Packet to execute. See HostAdapterStatus,
862 TargetStatus, SenseDataLength, and SenseData in
863 that order for additional status information.
866 SCSI_IO_DEV
*ScsiIoDevice
;
868 UINT8 Target
[TARGET_MAX_BYTES
];
869 EFI_EVENT PacketEvent
;
870 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ExtRequestPacket
;
871 SCSI_EVENT_DATA EventData
;
875 if (Packet
== NULL
) {
876 return EFI_INVALID_PARAMETER
;
879 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
880 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
882 if (ScsiIoDevice
->ExtScsiSupport
) {
883 ExtRequestPacket
= (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*) Packet
;
884 Status
= ScsiIoDevice
->ExtScsiPassThru
->PassThru (
885 ScsiIoDevice
->ExtScsiPassThru
,
893 Status
= gBS
->AllocatePool (
895 sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
),
896 (VOID
**)&WorkingBuffer
899 if (EFI_ERROR (Status
)) {
900 return EFI_DEVICE_ERROR
;
904 // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.
906 Status
= ScsiioToPassThruPacket(Packet
, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
);
907 if (EFI_ERROR(Status
)) {
908 gBS
->FreePool(WorkingBuffer
);
912 if ((ScsiIoDevice
->ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO
) && (Event
!= NULL
)) {
913 EventData
.Data1
= (VOID
*)Packet
;
914 EventData
.Data2
= Event
;
918 Status
= gBS
->CreateEvent (
925 if (EFI_ERROR(Status
)) {
926 gBS
->FreePool(WorkingBuffer
);
930 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
931 ScsiIoDevice
->ScsiPassThru
,
932 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
938 if (EFI_ERROR(Status
)) {
939 gBS
->FreePool(WorkingBuffer
);
940 gBS
->CloseEvent(PacketEvent
);
946 // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert
947 // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.
949 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
950 ScsiIoDevice
->ScsiPassThru
,
951 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
956 if (EFI_ERROR(Status
)) {
957 gBS
->FreePool(WorkingBuffer
);
961 PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
,Packet
);
963 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
964 // free WorkingBuffer.
966 gBS
->FreePool(WorkingBuffer
);
974 ScsiScanCreateDevice (
975 EFI_DRIVER_BINDING_PROTOCOL
*This
,
976 EFI_HANDLE Controller
,
977 SCSI_TARGET_ID
*TargetId
,
979 SCSI_BUS_DEVICE
*ScsiBusDev
985 Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.
989 This - Protocol instance pointer
990 Controller - Controller handle
991 Pun - The Pun of the SCSI device on the SCSI channel.
992 Lun - The Lun of the SCSI device on the SCSI channel.
993 ScsiBusDev - The pointer of SCSI_BUS_DEVICE
997 EFI_SUCCESS - Successfully to discover the device and attach ScsiIoProtocol to it.
998 EFI_OUT_OF_RESOURCES - Fail to discover the device.
1003 SCSI_IO_DEV
*ScsiIoDevice
;
1004 EFI_DEVICE_PATH_PROTOCOL
*ScsiDevicePath
;
1006 Status
= gBS
->AllocatePool (
1007 EfiBootServicesData
,
1008 sizeof (SCSI_IO_DEV
),
1009 (VOID
**) &ScsiIoDevice
1011 if (EFI_ERROR (Status
)) {
1015 ZeroMem (ScsiIoDevice
, sizeof (SCSI_IO_DEV
));
1017 ScsiIoDevice
->Signature
= SCSI_IO_DEV_SIGNATURE
;
1018 CopyMem(&ScsiIoDevice
->Pun
, TargetId
, TARGET_MAX_BYTES
);
1019 ScsiIoDevice
->Lun
= Lun
;
1021 if (ScsiBusDev
->ExtScsiSupport
) {
1022 ScsiIoDevice
->ExtScsiPassThru
= ScsiBusDev
->ExtScsiInterface
;
1023 ScsiIoDevice
->ExtScsiSupport
= TRUE
;
1024 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ExtScsiPassThru
->Mode
->IoAlign
;
1027 ScsiIoDevice
->ScsiPassThru
= ScsiBusDev
->ScsiInterface
;
1028 ScsiIoDevice
->ExtScsiSupport
= FALSE
;
1029 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ScsiPassThru
->Mode
->IoAlign
;
1032 ScsiIoDevice
->ScsiIo
.GetDeviceType
= ScsiGetDeviceType
;
1033 ScsiIoDevice
->ScsiIo
.GetDeviceLocation
= ScsiGetDeviceLocation
;
1034 ScsiIoDevice
->ScsiIo
.ResetBus
= ScsiResetBus
;
1035 ScsiIoDevice
->ScsiIo
.ResetDevice
= ScsiResetDevice
;
1036 ScsiIoDevice
->ScsiIo
.ExecuteScsiCommand
= ScsiExecuteSCSICommand
;
1039 if (!DiscoverScsiDevice (ScsiIoDevice
)) {
1040 gBS
->FreePool (ScsiIoDevice
);
1041 return EFI_OUT_OF_RESOURCES
;
1047 if (ScsiIoDevice
->ExtScsiSupport
){
1048 Status
= ScsiIoDevice
->ExtScsiPassThru
->BuildDevicePath (
1049 ScsiIoDevice
->ExtScsiPassThru
,
1050 &ScsiIoDevice
->Pun
.ScsiId
.ExtScsi
[0],
1054 if (Status
== EFI_OUT_OF_RESOURCES
) {
1055 gBS
->FreePool (ScsiIoDevice
);
1059 Status
= ScsiIoDevice
->ScsiPassThru
->BuildDevicePath (
1060 ScsiIoDevice
->ScsiPassThru
,
1061 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
1065 if (Status
== EFI_OUT_OF_RESOURCES
) {
1066 gBS
->FreePool (ScsiIoDevice
);
1071 ScsiIoDevice
->DevicePath
= AppendDevicePathNode (
1072 ScsiBusDev
->DevicePath
,
1076 // The memory space for ScsiDevicePath is allocated in
1077 // ScsiPassThru->BuildDevicePath() function; It is no longer used
1078 // after EfiAppendDevicePathNode,so free the memory it occupies.
1080 gBS
->FreePool (ScsiDevicePath
);
1082 if (ScsiIoDevice
->DevicePath
== NULL
) {
1083 gBS
->FreePool (ScsiIoDevice
);
1084 return EFI_OUT_OF_RESOURCES
;
1087 Status
= gBS
->InstallMultipleProtocolInterfaces (
1088 &ScsiIoDevice
->Handle
,
1089 &gEfiDevicePathProtocolGuid
,
1090 ScsiIoDevice
->DevicePath
,
1091 &gEfiScsiIoProtocolGuid
,
1092 &ScsiIoDevice
->ScsiIo
,
1095 if (EFI_ERROR (Status
)) {
1096 gBS
->FreePool (ScsiIoDevice
);
1097 return EFI_OUT_OF_RESOURCES
;
1099 if (ScsiBusDev
->ExtScsiSupport
) {
1102 &gEfiExtScsiPassThruProtocolGuid
,
1103 (VOID
**) &(ScsiBusDev
->ExtScsiInterface
),
1104 This
->DriverBindingHandle
,
1105 ScsiIoDevice
->Handle
,
1106 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1111 &gEfiScsiPassThruProtocolGuid
,
1112 (VOID
**) &(ScsiBusDev
->ScsiInterface
),
1113 This
->DriverBindingHandle
,
1114 ScsiIoDevice
->Handle
,
1115 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1124 DiscoverScsiDevice (
1125 SCSI_IO_DEV
*ScsiIoDevice
1129 Routine Description:
1131 Discovery SCSI Device
1135 ScsiIoDevice - The pointer of SCSI_IO_DEV
1139 TRUE - Find SCSI Device and verify it.
1140 FALSE - Unable to find SCSI Device.
1145 UINT32 InquiryDataLength
;
1146 UINT8 SenseDataLength
;
1147 UINT8 HostAdapterStatus
;
1149 EFI_SCSI_SENSE_DATA SenseData
;
1150 EFI_SCSI_INQUIRY_DATA InquiryData
;
1152 HostAdapterStatus
= 0;
1155 // Using Inquiry command to scan for the device
1157 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1158 SenseDataLength
= sizeof (EFI_SCSI_SENSE_DATA
);
1160 Status
= ScsiInquiryCommand (
1161 &ScsiIoDevice
->ScsiIo
,
1162 EfiScsiStallSeconds (1),
1163 (VOID
*) &SenseData
,
1167 (VOID
*) &InquiryData
,
1171 if (EFI_ERROR (Status
)) {
1173 // ParseSenseData (&SenseData,SenseDataLength);
1178 // Retrieved inquiry data successfully
1180 if ((InquiryData
.Peripheral_Qualifier
!= 0) &&
1181 (InquiryData
.Peripheral_Qualifier
!= 3)) {
1185 if (InquiryData
.Peripheral_Qualifier
== 3) {
1186 if (InquiryData
.Peripheral_Type
!= 0x1f) {
1191 if (0x1e >= InquiryData
.Peripheral_Type
&& InquiryData
.Peripheral_Type
>= 0xa) {
1196 // valid device type and peripheral qualifier combination.
1198 ScsiIoDevice
->ScsiDeviceType
= InquiryData
.Peripheral_Type
;
1199 ScsiIoDevice
->RemovableDevice
= InquiryData
.RMB
;
1200 if (InquiryData
.Version
== 0) {
1201 ScsiIoDevice
->ScsiVersion
= 0;
1204 // ANSI-approved version
1206 ScsiIoDevice
->ScsiVersion
= (UINT8
) (InquiryData
.Version
& 0x03);
1216 ScsiioToPassThruPacket (
1217 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
1218 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
1222 Routine Description:
1224 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to
1225 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet
1229 Packet - The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1230 CommandPacket - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1239 //EFI 1.10 doesn't support Bi-Direction Command.
1241 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL
) {
1242 return EFI_UNSUPPORTED
;
1245 ZeroMem (CommandPacket
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1247 CommandPacket
->Timeout
= Packet
->Timeout
;
1248 CommandPacket
->Cdb
= Packet
->Cdb
;
1249 CommandPacket
->CdbLength
= Packet
->CdbLength
;
1250 CommandPacket
->DataDirection
= Packet
->DataDirection
;
1251 CommandPacket
->HostAdapterStatus
= Packet
->HostAdapterStatus
;
1252 CommandPacket
->TargetStatus
= Packet
->TargetStatus
;
1253 CommandPacket
->SenseData
= Packet
->SenseData
;
1254 CommandPacket
->SenseDataLength
= Packet
->SenseDataLength
;
1256 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1257 CommandPacket
->DataBuffer
= Packet
->InDataBuffer
;
1258 CommandPacket
->TransferLength
= Packet
->InTransferLength
;
1259 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1260 CommandPacket
->DataBuffer
= Packet
->OutDataBuffer
;
1261 CommandPacket
->TransferLength
= Packet
->OutTransferLength
;
1270 PassThruToScsiioPacket (
1271 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
1272 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
1276 Routine Description:
1278 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to
1279 EFI_SCSI_IO_SCSI_REQUEST_PACKET packet
1283 ScsiPacket - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1284 Packet - The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1292 Packet
->Timeout
= ScsiPacket
->Timeout
;
1293 Packet
->Cdb
= ScsiPacket
->Cdb
;
1294 Packet
->CdbLength
= ScsiPacket
->CdbLength
;
1295 Packet
->DataDirection
= ScsiPacket
->DataDirection
;
1296 Packet
->HostAdapterStatus
= ScsiPacket
->HostAdapterStatus
;
1297 Packet
->TargetStatus
= ScsiPacket
->TargetStatus
;
1298 Packet
->SenseData
= ScsiPacket
->SenseData
;
1299 Packet
->SenseDataLength
= ScsiPacket
->SenseDataLength
;
1301 if (ScsiPacket
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1302 Packet
->InDataBuffer
= ScsiPacket
->DataBuffer
;
1303 Packet
->InTransferLength
= ScsiPacket
->TransferLength
;
1304 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1305 Packet
->OutDataBuffer
= ScsiPacket
->DataBuffer
;
1306 Packet
->OutTransferLength
= ScsiPacket
->TransferLength
;
1323 Routine Description:
1325 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
1330 Event - The instance of EFI_EVENT.
1331 Context - The parameter passed in.
1339 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
;
1340 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
;
1341 EFI_EVENT CallerEvent
;
1342 SCSI_EVENT_DATA
*PassData
;
1344 PassData
= (SCSI_EVENT_DATA
*)Context
;
1345 Packet
= (EFI_SCSI_IO_SCSI_REQUEST_PACKET
*)PassData
->Data1
;
1346 ScsiPacket
= (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
;
1349 // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.
1351 PassThruToScsiioPacket(ScsiPacket
, Packet
);
1354 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1355 // free WorkingBuffer.
1357 gBS
->FreePool(WorkingBuffer
);
1360 // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.
1362 CallerEvent
= PassData
->Data2
;
1363 gBS
->CloseEvent(Event
);
1364 gBS
->SignalEvent(CallerEvent
);