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
69 PassThruToScsiioPacket (
70 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
71 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
82 The user Entry Point for module ScsiBus. The user code starts with this function.
84 @param[in] ImageHandle The firmware allocated handle for the EFI image.
85 @param[in] SystemTable A pointer to the EFI System Table.
87 @retval EFI_SUCCESS The entry point is executed successfully.
88 @retval other Some error occurs when executing this entry point.
94 IN EFI_HANDLE ImageHandle
,
95 IN EFI_SYSTEM_TABLE
*SystemTable
101 // Install driver model protocol(s).
103 Status
= EfiLibInstallDriverBindingComponentName2 (
106 &gSCSIBusDriverBinding
,
108 &gScsiBusComponentName
,
109 &gScsiBusComponentName2
111 ASSERT_EFI_ERROR (Status
);
118 SCSIBusDriverBindingSupported (
119 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
120 IN EFI_HANDLE Controller
,
121 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
127 Test to see if this driver supports ControllerHandle. Any ControllerHandle
128 that has ExtScsiPassThruProtocol/ScsiPassThruProtocol installed will be supported.
132 This - Protocol instance pointer.
133 Controller - Handle of device to test
134 RemainingDevicePath - Not used
138 EFI_SUCCESS - This driver supports this device.
139 EFI_UNSUPPORTED - This driver does not support this device.
145 EFI_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
146 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtPassThru
;
148 // Check for the existence of Extended SCSI Pass Thru Protocol and SCSI Pass Thru Protocol
150 Status
= gBS
->OpenProtocol (
152 &gEfiExtScsiPassThruProtocolGuid
,
153 (VOID
**)&ExtPassThru
,
154 This
->DriverBindingHandle
,
156 EFI_OPEN_PROTOCOL_BY_DRIVER
159 if (Status
== EFI_ALREADY_STARTED
) {
163 if (EFI_ERROR (Status
)) {
164 Status
= gBS
->OpenProtocol (
166 &gEfiScsiPassThruProtocolGuid
,
168 This
->DriverBindingHandle
,
170 EFI_OPEN_PROTOCOL_BY_DRIVER
173 if (Status
== EFI_ALREADY_STARTED
) {
177 if (EFI_ERROR (Status
)) {
183 &gEfiScsiPassThruProtocolGuid
,
184 This
->DriverBindingHandle
,
192 &gEfiExtScsiPassThruProtocolGuid
,
193 This
->DriverBindingHandle
,
202 SCSIBusDriverBindingStart (
203 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
204 IN EFI_HANDLE Controller
,
205 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
210 Starting the SCSI Bus Driver
213 This - Protocol instance pointer.
214 Controller - Handle of device to test
215 RemainingDevicePath - Not used
218 EFI_SUCCESS - This driver supports this device.
219 EFI_UNSUPPORTED - This driver does not support this device.
220 EFI_DEVICE_ERROR - This driver cannot be started due to device Error
226 BOOLEAN ScanOtherPuns
;
227 BOOLEAN FromFirstTarget
;
228 BOOLEAN ExtScsiSupport
;
230 EFI_STATUS DevicePathStatus
;
231 EFI_STATUS PassThruStatus
;
232 SCSI_BUS_DEVICE
*ScsiBusDev
;
233 SCSI_TARGET_ID
*ScsiTargetId
;
234 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
235 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiInterface
;
236 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiInterface
;
237 EFI_SCSI_BUS_PROTOCOL
*BusIdentify
;
241 ScanOtherPuns
= TRUE
;
242 FromFirstTarget
= FALSE
;
243 ExtScsiSupport
= FALSE
;
244 PassThruStatus
= EFI_SUCCESS
;
246 ScsiTargetId
= AllocateZeroPool(sizeof(SCSI_TARGET_ID
));
247 if (ScsiTargetId
== NULL
) {
248 return EFI_OUT_OF_RESOURCES
;
251 TargetId
= &ScsiTargetId
->ScsiId
.ExtScsi
[0];
253 DevicePathStatus
= gBS
->OpenProtocol (
255 &gEfiDevicePathProtocolGuid
,
256 (VOID
**) &ParentDevicePath
,
257 This
->DriverBindingHandle
,
259 EFI_OPEN_PROTOCOL_BY_DRIVER
261 if (EFI_ERROR (DevicePathStatus
) && (DevicePathStatus
!= EFI_ALREADY_STARTED
)) {
262 return DevicePathStatus
;
266 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
267 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
268 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
270 Status
= gBS
->OpenProtocol (
272 &gEfiExtScsiPassThruProtocolGuid
,
273 (VOID
**) &ExtScsiInterface
,
274 This
->DriverBindingHandle
,
276 EFI_OPEN_PROTOCOL_BY_DRIVER
279 // Fail to open UEFI ExtendPassThru Protocol, then try to open EFI PassThru Protocol instead.
281 if (EFI_ERROR(Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
282 Status
= gBS
->OpenProtocol (
284 &gEfiScsiPassThruProtocolGuid
,
285 (VOID
**) &ScsiInterface
,
286 This
->DriverBindingHandle
,
288 EFI_OPEN_PROTOCOL_BY_DRIVER
291 // Fail to open EFI PassThru Protocol, Close the DevicePathProtocol if it is opened by this time.
293 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
294 if (!EFI_ERROR(DevicePathStatus
)) {
297 &gEfiDevicePathProtocolGuid
,
298 This
->DriverBindingHandle
,
306 // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol
307 // with BY_DRIVER if it is also present on the handle. The intent is to prevent
308 // another SCSI Bus Driver to work on the same host handle.
310 ExtScsiSupport
= TRUE
;
311 PassThruStatus
= gBS
->OpenProtocol (
313 &gEfiScsiPassThruProtocolGuid
,
314 (VOID
**) &ScsiInterface
,
315 This
->DriverBindingHandle
,
317 EFI_OPEN_PROTOCOL_BY_DRIVER
321 if (Status
!= EFI_ALREADY_STARTED
) {
323 // Go through here means either ExtPassThru or PassThru Protocol is successfully opened
324 // on this handle for this time. Then construct Host controller private data.
327 ScsiBusDev
= AllocateZeroPool(sizeof(SCSI_BUS_DEVICE
));
328 if (ScsiBusDev
== NULL
) {
329 Status
= EFI_OUT_OF_RESOURCES
;
332 ScsiBusDev
->Signature
= SCSI_BUS_DEVICE_SIGNATURE
;
333 ScsiBusDev
->ExtScsiSupport
= ExtScsiSupport
;
334 ScsiBusDev
->DevicePath
= ParentDevicePath
;
335 if (ScsiBusDev
->ExtScsiSupport
) {
336 ScsiBusDev
->ExtScsiInterface
= ExtScsiInterface
;
338 ScsiBusDev
->ScsiInterface
= ScsiInterface
;
342 // Install EFI_SCSI_BUS_PROTOCOL to the controller handle, So ScsiBusDev could be
343 // retrieved on this controller handle. With ScsiBusDev, we can know which PassThru
344 // Protocol is present on the handle, UEFI ExtPassThru Protocol or EFI PassThru Protocol.
346 Status
= gBS
->InstallProtocolInterface (
348 &mScsiBusProtocolGuid
,
349 EFI_NATIVE_INTERFACE
,
350 &ScsiBusDev
->BusIdentify
352 if (EFI_ERROR (Status
)) {
357 // Go through here means Start() is re-invoked again, nothing special is required to do except
358 // picking up Host controller private information.
360 Status
= gBS
->OpenProtocol (
362 &mScsiBusProtocolGuid
,
363 (VOID
**) &BusIdentify
,
364 This
->DriverBindingHandle
,
366 EFI_OPEN_PROTOCOL_GET_PROTOCOL
369 if (EFI_ERROR (Status
)) {
372 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify
);
375 if (RemainingDevicePath
== NULL
) {
376 SetMem (ScsiTargetId
, TARGET_MAX_BYTES
,0xFF);
378 FromFirstTarget
= TRUE
;
380 if (ScsiBusDev
->ExtScsiSupport
) {
381 ScsiBusDev
->ExtScsiInterface
->GetTargetLun (ScsiBusDev
->ExtScsiInterface
, RemainingDevicePath
, &TargetId
, &Lun
);
383 ScsiBusDev
->ScsiInterface
->GetTargetLun (ScsiBusDev
->ScsiInterface
, RemainingDevicePath
, &ScsiTargetId
->ScsiId
.Scsi
, &Lun
);
387 while(ScanOtherPuns
) {
388 if (FromFirstTarget
) {
390 // Remaining Device Path is NULL, scan all the possible Puns in the
393 if (ScsiBusDev
->ExtScsiSupport
) {
394 Status
= ScsiBusDev
->ExtScsiInterface
->GetNextTargetLun (ScsiBusDev
->ExtScsiInterface
, &TargetId
, &Lun
);
396 Status
= ScsiBusDev
->ScsiInterface
->GetNextDevice (ScsiBusDev
->ScsiInterface
, &ScsiTargetId
->ScsiId
.Scsi
, &Lun
);
398 if (EFI_ERROR (Status
)) {
400 // no legal Pun and Lun found any more
405 ScanOtherPuns
= FALSE
;
408 // Avoid creating handle for the host adapter.
410 if (ScsiBusDev
->ExtScsiSupport
) {
411 if ((ScsiTargetId
->ScsiId
.Scsi
) == ScsiBusDev
->ExtScsiInterface
->Mode
->AdapterId
) {
415 if ((ScsiTargetId
->ScsiId
.Scsi
) == ScsiBusDev
->ScsiInterface
->Mode
->AdapterId
) {
420 // Scan for the scsi device, if it attaches to the scsi bus,
421 // then create handle and install scsi i/o protocol.
423 Status
= ScsiScanCreateDevice (This
, Controller
, ScsiTargetId
, Lun
, ScsiBusDev
);
425 gBS
->FreePool (ScsiTargetId
);
430 if (ScsiBusDev
!= NULL
) {
431 gBS
->FreePool (ScsiBusDev
);
434 if (ExtScsiSupport
) {
437 &gEfiExtScsiPassThruProtocolGuid
,
438 This
->DriverBindingHandle
,
441 if (!EFI_ERROR (PassThruStatus
)) {
444 &gEfiScsiPassThruProtocolGuid
,
445 This
->DriverBindingHandle
,
452 &gEfiScsiPassThruProtocolGuid
,
453 This
->DriverBindingHandle
,
462 SCSIBusDriverBindingStop (
463 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
464 IN EFI_HANDLE Controller
,
465 IN UINTN NumberOfChildren
,
466 IN EFI_HANDLE
*ChildHandleBuffer
472 Stop this driver on ControllerHandle. Support stoping any child handles
473 created by this driver.
477 This - Protocol instance pointer.
478 Controller - Handle of device to stop driver on
479 NumberOfChildren - Number of Children in the ChildHandleBuffer
480 ChildHandleBuffer - List of handles for the children we need to stop.
489 BOOLEAN AllChildrenStopped
;
491 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
492 SCSI_IO_DEV
*ScsiIoDevice
;
494 EFI_SCSI_BUS_PROTOCOL
*Scsidentifier
;
495 SCSI_BUS_DEVICE
*ScsiBusDev
;
497 if (NumberOfChildren
== 0) {
499 // Get the SCSI_BUS_DEVICE
501 Status
= gBS
->OpenProtocol (
503 &mScsiBusProtocolGuid
,
504 (VOID
**) &Scsidentifier
,
505 This
->DriverBindingHandle
,
507 EFI_OPEN_PROTOCOL_GET_PROTOCOL
510 if (EFI_ERROR (Status
)) {
511 return EFI_DEVICE_ERROR
;
514 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier
);
517 // Uninstall SCSI Bus Protocol
519 gBS
->UninstallProtocolInterface (
521 &mScsiBusProtocolGuid
,
522 &ScsiBusDev
->BusIdentify
526 // Close the bus driver
528 if (ScsiBusDev
->ExtScsiSupport
) {
531 &gEfiExtScsiPassThruProtocolGuid
,
532 This
->DriverBindingHandle
,
538 &gEfiScsiPassThruProtocolGuid
,
539 This
->DriverBindingHandle
,
546 &gEfiDevicePathProtocolGuid
,
547 This
->DriverBindingHandle
,
550 gBS
->FreePool (ScsiBusDev
);
554 AllChildrenStopped
= TRUE
;
556 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
558 Status
= gBS
->OpenProtocol (
559 ChildHandleBuffer
[Index
],
560 &gEfiScsiIoProtocolGuid
,
562 This
->DriverBindingHandle
,
564 EFI_OPEN_PROTOCOL_GET_PROTOCOL
566 if (EFI_ERROR (Status
)) {
567 AllChildrenStopped
= FALSE
;
571 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (ScsiIo
);
573 // Close the child handle
575 if (ScsiIoDevice
->ExtScsiSupport
) {
576 Status
= gBS
->CloseProtocol (
578 &gEfiExtScsiPassThruProtocolGuid
,
579 This
->DriverBindingHandle
,
580 ChildHandleBuffer
[Index
]
584 Status
= gBS
->CloseProtocol (
586 &gEfiScsiPassThruProtocolGuid
,
587 This
->DriverBindingHandle
,
588 ChildHandleBuffer
[Index
]
592 Status
= gBS
->UninstallMultipleProtocolInterfaces (
593 ChildHandleBuffer
[Index
],
594 &gEfiDevicePathProtocolGuid
,
595 ScsiIoDevice
->DevicePath
,
596 &gEfiScsiIoProtocolGuid
,
597 &ScsiIoDevice
->ScsiIo
,
600 if (EFI_ERROR (Status
)) {
601 AllChildrenStopped
= FALSE
;
602 if (ScsiIoDevice
->ExtScsiSupport
) {
605 &gEfiExtScsiPassThruProtocolGuid
,
607 This
->DriverBindingHandle
,
608 ChildHandleBuffer
[Index
],
609 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
614 &gEfiScsiPassThruProtocolGuid
,
616 This
->DriverBindingHandle
,
617 ChildHandleBuffer
[Index
],
618 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
622 gBS
->FreePool (ScsiIoDevice
);
626 if (!AllChildrenStopped
) {
627 return EFI_DEVICE_ERROR
;
636 IN EFI_SCSI_IO_PROTOCOL
*This
,
637 OUT UINT8
*DeviceType
643 Retrieves the device type information of the SCSI Controller.
647 This - Protocol instance pointer.
648 DeviceType - A pointer to the device type information
649 retrieved from the SCSI Controller.
653 EFI_SUCCESS - Retrieves the device type information successfully.
654 EFI_INVALID_PARAMETER - The DeviceType is NULL.
658 SCSI_IO_DEV
*ScsiIoDevice
;
660 if (DeviceType
== NULL
) {
661 return EFI_INVALID_PARAMETER
;
664 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
665 *DeviceType
= ScsiIoDevice
->ScsiDeviceType
;
671 ScsiGetDeviceLocation (
672 IN EFI_SCSI_IO_PROTOCOL
*This
,
673 IN OUT UINT8
**Target
,
680 Retrieves the device location in the SCSI channel.
684 This - Protocol instance pointer.
685 Target - A pointer to the Target Array which represents ID of a SCSI device
687 Lun - A pointer to the LUN of the SCSI device on
692 EFI_SUCCESS - Retrieves the device location successfully.
693 EFI_INVALID_PARAMETER - The Target or Lun is NULL.
697 SCSI_IO_DEV
*ScsiIoDevice
;
699 if (Target
== NULL
|| Lun
== NULL
) {
700 return EFI_INVALID_PARAMETER
;
703 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
705 CopyMem (*Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
707 *Lun
= ScsiIoDevice
->Lun
;
715 IN EFI_SCSI_IO_PROTOCOL
*This
721 Resets the SCSI Bus that the SCSI Controller is attached to.
725 This - Protocol instance pointer.
729 EFI_SUCCESS - The SCSI bus is reset successfully.
730 EFI_DEVICE_ERROR - Errors encountered when resetting the SCSI bus.
731 EFI_UNSUPPORTED - The bus reset operation is not supported by the
732 SCSI Host Controller.
733 EFI_TIMEOUT - A timeout occurred while attempting to reset
737 SCSI_IO_DEV
*ScsiIoDevice
;
739 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
741 if (ScsiIoDevice
->ExtScsiSupport
){
742 return ScsiIoDevice
->ExtScsiPassThru
->ResetChannel (ScsiIoDevice
->ExtScsiPassThru
);
744 return ScsiIoDevice
->ScsiPassThru
->ResetChannel (ScsiIoDevice
->ScsiPassThru
);
751 IN EFI_SCSI_IO_PROTOCOL
*This
757 Resets the SCSI Controller that the device handle specifies.
761 This - Protocol instance pointer.
765 EFI_SUCCESS - Reset the SCSI controller successfully.
766 EFI_DEVICE_ERROR - Errors are encountered when resetting the
768 EFI_UNSUPPORTED - The SCSI bus does not support a device
770 EFI_TIMEOUT - A timeout occurred while attempting to
771 reset the SCSI Controller.
774 SCSI_IO_DEV
*ScsiIoDevice
;
775 UINT8 Target
[TARGET_MAX_BYTES
];
777 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
778 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
781 if (ScsiIoDevice
->ExtScsiSupport
) {
782 return ScsiIoDevice
->ExtScsiPassThru
->ResetTargetLun (
783 ScsiIoDevice
->ExtScsiPassThru
,
788 return ScsiIoDevice
->ScsiPassThru
->ResetTarget (
789 ScsiIoDevice
->ScsiPassThru
,
790 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
798 ScsiExecuteSCSICommand (
799 IN EFI_SCSI_IO_PROTOCOL
*This
,
800 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
801 IN EFI_EVENT Event OPTIONAL
807 Sends a SCSI Request Packet to the SCSI Controller for execution.
811 This - Protocol instance pointer.
812 Packet - The SCSI request packet to send to the SCSI
813 Controller specified by the device handle.
814 Event - If the SCSI bus where the SCSI device is attached
815 does not support non-blocking I/O, then Event is
816 ignored, and blocking I/O is performed.
817 If Event is NULL, then blocking I/O is performed.
818 If Event is not NULL and non-blocking I/O is
819 supported, then non-blocking I/O is performed,
820 and Event will be signaled when the SCSI Request
824 EFI_SUCCESS - The SCSI Request Packet was sent by the host
825 successfully, and TransferLength bytes were
826 transferred to/from DataBuffer.See
827 HostAdapterStatus, TargetStatus,
828 SenseDataLength, and SenseData in that order
829 for additional status information.
830 EFI_BAD_BUFFER_SIZE - The SCSI Request Packet was executed,
831 but the entire DataBuffer could not be transferred.
832 The actual number of bytes transferred is returned
833 in TransferLength. See HostAdapterStatus,
834 TargetStatus, SenseDataLength, and SenseData in
835 that order for additional status information.
836 EFI_NOT_READY - The SCSI Request Packet could not be sent because
837 there are too many SCSI Command Packets already
838 queued.The caller may retry again later.
839 EFI_DEVICE_ERROR - A device error occurred while attempting to send
840 the SCSI Request Packet. See HostAdapterStatus,
841 TargetStatus, SenseDataLength, and SenseData in
842 that order for additional status information.
843 EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid.
844 The SCSI Request Packet was not sent, so no
845 additional status information is available.
846 EFI_UNSUPPORTED - The command described by the SCSI Request Packet
847 is not supported by the SCSI initiator(i.e., SCSI
848 Host Controller). The SCSI Request Packet was not
849 sent, so no additional status information is
851 EFI_TIMEOUT - A timeout occurred while waiting for the SCSI
852 Request Packet to execute. See HostAdapterStatus,
853 TargetStatus, SenseDataLength, and SenseData in
854 that order for additional status information.
857 SCSI_IO_DEV
*ScsiIoDevice
;
859 UINT8 Target
[TARGET_MAX_BYTES
];
860 EFI_EVENT PacketEvent
;
861 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ExtRequestPacket
;
862 SCSI_EVENT_DATA EventData
;
866 if (Packet
== NULL
) {
867 return EFI_INVALID_PARAMETER
;
870 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
871 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
873 if (ScsiIoDevice
->ExtScsiSupport
) {
874 ExtRequestPacket
= (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*) Packet
;
875 Status
= ScsiIoDevice
->ExtScsiPassThru
->PassThru (
876 ScsiIoDevice
->ExtScsiPassThru
,
884 Status
= gBS
->AllocatePool (
886 sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
),
887 (VOID
**)&WorkingBuffer
890 if (EFI_ERROR (Status
)) {
891 return EFI_DEVICE_ERROR
;
895 // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.
897 Status
= ScsiioToPassThruPacket(Packet
, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
);
898 if (EFI_ERROR(Status
)) {
899 gBS
->FreePool(WorkingBuffer
);
903 if ((ScsiIoDevice
->ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO
) && (Event
!= NULL
)) {
904 EventData
.Data1
= (VOID
*)Packet
;
905 EventData
.Data2
= Event
;
909 Status
= gBS
->CreateEvent (
916 if (EFI_ERROR(Status
)) {
917 gBS
->FreePool(WorkingBuffer
);
921 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
922 ScsiIoDevice
->ScsiPassThru
,
923 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
929 if (EFI_ERROR(Status
)) {
930 gBS
->FreePool(WorkingBuffer
);
931 gBS
->CloseEvent(PacketEvent
);
937 // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert
938 // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.
940 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
941 ScsiIoDevice
->ScsiPassThru
,
942 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
947 if (EFI_ERROR(Status
)) {
948 gBS
->FreePool(WorkingBuffer
);
952 PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
,Packet
);
954 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
955 // free WorkingBuffer.
957 gBS
->FreePool(WorkingBuffer
);
965 ScsiScanCreateDevice (
966 EFI_DRIVER_BINDING_PROTOCOL
*This
,
967 EFI_HANDLE Controller
,
968 SCSI_TARGET_ID
*TargetId
,
970 SCSI_BUS_DEVICE
*ScsiBusDev
976 Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.
980 This - Protocol instance pointer
981 Controller - Controller handle
982 Pun - The Pun of the SCSI device on the SCSI channel.
983 Lun - The Lun of the SCSI device on the SCSI channel.
984 ScsiBusDev - The pointer of SCSI_BUS_DEVICE
988 EFI_SUCCESS - Successfully to discover the device and attach ScsiIoProtocol to it.
989 EFI_OUT_OF_RESOURCES - Fail to discover the device.
994 SCSI_IO_DEV
*ScsiIoDevice
;
995 EFI_DEVICE_PATH_PROTOCOL
*ScsiDevicePath
;
997 Status
= gBS
->AllocatePool (
999 sizeof (SCSI_IO_DEV
),
1000 (VOID
**) &ScsiIoDevice
1002 if (EFI_ERROR (Status
)) {
1006 ZeroMem (ScsiIoDevice
, sizeof (SCSI_IO_DEV
));
1008 ScsiIoDevice
->Signature
= SCSI_IO_DEV_SIGNATURE
;
1009 CopyMem(&ScsiIoDevice
->Pun
, TargetId
, TARGET_MAX_BYTES
);
1010 ScsiIoDevice
->Lun
= Lun
;
1012 if (ScsiBusDev
->ExtScsiSupport
) {
1013 ScsiIoDevice
->ExtScsiPassThru
= ScsiBusDev
->ExtScsiInterface
;
1014 ScsiIoDevice
->ExtScsiSupport
= TRUE
;
1015 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ExtScsiPassThru
->Mode
->IoAlign
;
1018 ScsiIoDevice
->ScsiPassThru
= ScsiBusDev
->ScsiInterface
;
1019 ScsiIoDevice
->ExtScsiSupport
= FALSE
;
1020 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ScsiPassThru
->Mode
->IoAlign
;
1023 ScsiIoDevice
->ScsiIo
.GetDeviceType
= ScsiGetDeviceType
;
1024 ScsiIoDevice
->ScsiIo
.GetDeviceLocation
= ScsiGetDeviceLocation
;
1025 ScsiIoDevice
->ScsiIo
.ResetBus
= ScsiResetBus
;
1026 ScsiIoDevice
->ScsiIo
.ResetDevice
= ScsiResetDevice
;
1027 ScsiIoDevice
->ScsiIo
.ExecuteScsiCommand
= ScsiExecuteSCSICommand
;
1030 if (!DiscoverScsiDevice (ScsiIoDevice
)) {
1031 gBS
->FreePool (ScsiIoDevice
);
1032 return EFI_OUT_OF_RESOURCES
;
1038 if (ScsiIoDevice
->ExtScsiSupport
){
1039 Status
= ScsiIoDevice
->ExtScsiPassThru
->BuildDevicePath (
1040 ScsiIoDevice
->ExtScsiPassThru
,
1041 &ScsiIoDevice
->Pun
.ScsiId
.ExtScsi
[0],
1045 if (Status
== EFI_OUT_OF_RESOURCES
) {
1046 gBS
->FreePool (ScsiIoDevice
);
1050 Status
= ScsiIoDevice
->ScsiPassThru
->BuildDevicePath (
1051 ScsiIoDevice
->ScsiPassThru
,
1052 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
1056 if (Status
== EFI_OUT_OF_RESOURCES
) {
1057 gBS
->FreePool (ScsiIoDevice
);
1062 ScsiIoDevice
->DevicePath
= AppendDevicePathNode (
1063 ScsiBusDev
->DevicePath
,
1067 // The memory space for ScsiDevicePath is allocated in
1068 // ScsiPassThru->BuildDevicePath() function; It is no longer used
1069 // after EfiAppendDevicePathNode,so free the memory it occupies.
1071 gBS
->FreePool (ScsiDevicePath
);
1073 if (ScsiIoDevice
->DevicePath
== NULL
) {
1074 gBS
->FreePool (ScsiIoDevice
);
1075 return EFI_OUT_OF_RESOURCES
;
1078 Status
= gBS
->InstallMultipleProtocolInterfaces (
1079 &ScsiIoDevice
->Handle
,
1080 &gEfiDevicePathProtocolGuid
,
1081 ScsiIoDevice
->DevicePath
,
1082 &gEfiScsiIoProtocolGuid
,
1083 &ScsiIoDevice
->ScsiIo
,
1086 if (EFI_ERROR (Status
)) {
1087 gBS
->FreePool (ScsiIoDevice
);
1088 return EFI_OUT_OF_RESOURCES
;
1090 if (ScsiBusDev
->ExtScsiSupport
) {
1093 &gEfiExtScsiPassThruProtocolGuid
,
1094 (VOID
**) &(ScsiBusDev
->ExtScsiInterface
),
1095 This
->DriverBindingHandle
,
1096 ScsiIoDevice
->Handle
,
1097 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1102 &gEfiScsiPassThruProtocolGuid
,
1103 (VOID
**) &(ScsiBusDev
->ScsiInterface
),
1104 This
->DriverBindingHandle
,
1105 ScsiIoDevice
->Handle
,
1106 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1115 DiscoverScsiDevice (
1116 SCSI_IO_DEV
*ScsiIoDevice
1120 Routine Description:
1122 Discovery SCSI Device
1126 ScsiIoDevice - The pointer of SCSI_IO_DEV
1130 TRUE - Find SCSI Device and verify it.
1131 FALSE - Unable to find SCSI Device.
1136 UINT32 InquiryDataLength
;
1137 UINT8 SenseDataLength
;
1138 UINT8 HostAdapterStatus
;
1140 EFI_SCSI_SENSE_DATA SenseData
;
1141 EFI_SCSI_INQUIRY_DATA InquiryData
;
1143 HostAdapterStatus
= 0;
1146 // Using Inquiry command to scan for the device
1148 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1149 SenseDataLength
= sizeof (EFI_SCSI_SENSE_DATA
);
1151 Status
= ScsiInquiryCommand (
1152 &ScsiIoDevice
->ScsiIo
,
1153 EfiScsiStallSeconds (1),
1154 (VOID
*) &SenseData
,
1158 (VOID
*) &InquiryData
,
1162 if (EFI_ERROR (Status
)) {
1164 // ParseSenseData (&SenseData,SenseDataLength);
1169 // Retrieved inquiry data successfully
1171 if ((InquiryData
.Peripheral_Qualifier
!= 0) &&
1172 (InquiryData
.Peripheral_Qualifier
!= 3)) {
1176 if (InquiryData
.Peripheral_Qualifier
== 3) {
1177 if (InquiryData
.Peripheral_Type
!= 0x1f) {
1182 if (0x1e >= InquiryData
.Peripheral_Type
&& InquiryData
.Peripheral_Type
>= 0xa) {
1187 // valid device type and peripheral qualifier combination.
1189 ScsiIoDevice
->ScsiDeviceType
= InquiryData
.Peripheral_Type
;
1190 ScsiIoDevice
->RemovableDevice
= InquiryData
.RMB
;
1191 if (InquiryData
.Version
== 0) {
1192 ScsiIoDevice
->ScsiVersion
= 0;
1195 // ANSI-approved version
1197 ScsiIoDevice
->ScsiVersion
= (UINT8
) (InquiryData
.Version
& 0x03);
1207 ScsiioToPassThruPacket (
1208 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
1209 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
1213 Routine Description:
1215 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to
1216 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet
1220 Packet - The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1221 CommandPacket - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1230 //EFI 1.10 doesn't support Bi-Direction Command.
1232 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL
) {
1233 return EFI_UNSUPPORTED
;
1236 ZeroMem (CommandPacket
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1238 CommandPacket
->Timeout
= Packet
->Timeout
;
1239 CommandPacket
->Cdb
= Packet
->Cdb
;
1240 CommandPacket
->CdbLength
= Packet
->CdbLength
;
1241 CommandPacket
->DataDirection
= Packet
->DataDirection
;
1242 CommandPacket
->HostAdapterStatus
= Packet
->HostAdapterStatus
;
1243 CommandPacket
->TargetStatus
= Packet
->TargetStatus
;
1244 CommandPacket
->SenseData
= Packet
->SenseData
;
1245 CommandPacket
->SenseDataLength
= Packet
->SenseDataLength
;
1247 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1248 CommandPacket
->DataBuffer
= Packet
->InDataBuffer
;
1249 CommandPacket
->TransferLength
= Packet
->InTransferLength
;
1250 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1251 CommandPacket
->DataBuffer
= Packet
->OutDataBuffer
;
1252 CommandPacket
->TransferLength
= Packet
->OutTransferLength
;
1261 PassThruToScsiioPacket (
1262 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
1263 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
1267 Routine Description:
1269 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to
1270 EFI_SCSI_IO_SCSI_REQUEST_PACKET packet
1274 ScsiPacket - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1275 Packet - The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1283 Packet
->Timeout
= ScsiPacket
->Timeout
;
1284 Packet
->Cdb
= ScsiPacket
->Cdb
;
1285 Packet
->CdbLength
= ScsiPacket
->CdbLength
;
1286 Packet
->DataDirection
= ScsiPacket
->DataDirection
;
1287 Packet
->HostAdapterStatus
= ScsiPacket
->HostAdapterStatus
;
1288 Packet
->TargetStatus
= ScsiPacket
->TargetStatus
;
1289 Packet
->SenseData
= ScsiPacket
->SenseData
;
1290 Packet
->SenseDataLength
= ScsiPacket
->SenseDataLength
;
1292 if (ScsiPacket
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1293 Packet
->InDataBuffer
= ScsiPacket
->DataBuffer
;
1294 Packet
->InTransferLength
= ScsiPacket
->TransferLength
;
1295 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1296 Packet
->OutDataBuffer
= ScsiPacket
->DataBuffer
;
1297 Packet
->OutTransferLength
= ScsiPacket
->TransferLength
;
1314 Routine Description:
1316 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
1321 Event - The instance of EFI_EVENT.
1322 Context - The parameter passed in.
1330 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
;
1331 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
;
1332 EFI_EVENT CallerEvent
;
1333 SCSI_EVENT_DATA
*PassData
;
1335 PassData
= (SCSI_EVENT_DATA
*)Context
;
1336 Packet
= (EFI_SCSI_IO_SCSI_REQUEST_PACKET
*)PassData
->Data1
;
1337 ScsiPacket
= (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
;
1340 // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.
1342 PassThruToScsiioPacket(ScsiPacket
, Packet
);
1345 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1346 // free WorkingBuffer.
1348 gBS
->FreePool(WorkingBuffer
);
1351 // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.
1353 CallerEvent
= PassData
->Data2
;
1354 gBS
->CloseEvent(Event
);
1355 gBS
->SignalEvent(CallerEvent
);