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.
23 // The package level header files this module uses
28 // The protocols, PPI and GUID defintions for this module
30 #include <Protocol/ScsiPassThru.h>
31 #include <Protocol/ScsiPassThruExt.h>
32 #include <Protocol/ScsiIo.h>
33 #include <Protocol/ComponentName.h>
34 #include <Protocol/DriverBinding.h>
35 #include <Protocol/DevicePath.h>
37 // The Library classes this module consumes
39 #include <Library/DebugLib.h>
40 #include <Library/UefiDriverEntryPoint.h>
41 #include <Library/UefiLib.h>
42 #include <Library/BaseMemoryLib.h>
43 #include <Library/MemoryAllocationLib.h>
44 #include <Library/ScsiLib.h>
45 #include <Library/UefiBootServicesTableLib.h>
46 #include <Library/DevicePathLib.h>
50 EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding
= {
51 SCSIBusDriverBindingSupported
,
52 SCSIBusDriverBindingStart
,
53 SCSIBusDriverBindingStop
,
61 // The ScsiBusProtocol is just used to locate ScsiBusDev
62 // structure in the SCSIBusDriverBindingStop(). Then we can
63 // Close all opened protocols and release this structure.
65 STATIC EFI_GUID mScsiBusProtocolGuid
= EFI_SCSI_BUS_PROTOCOL_GUID
;
67 STATIC VOID
*WorkingBuffer
;
72 ScsiioToPassThruPacket (
73 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
74 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
82 PassThruToScsiioPacket (
83 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
84 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
97 The user Entry Point for module ScsiBus. The user code starts with this function.
99 @param[in] ImageHandle The firmware allocated handle for the EFI image.
100 @param[in] SystemTable A pointer to the EFI System Table.
102 @retval EFI_SUCCESS The entry point is executed successfully.
103 @retval other Some error occurs when executing this entry point.
109 IN EFI_HANDLE ImageHandle
,
110 IN EFI_SYSTEM_TABLE
*SystemTable
116 // Install driver model protocol(s).
118 Status
= EfiLibInstallAllDriverProtocols (
121 &gSCSIBusDriverBinding
,
123 &gScsiBusComponentName
,
127 ASSERT_EFI_ERROR (Status
);
135 SCSIBusDriverBindingSupported (
136 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
137 IN EFI_HANDLE Controller
,
138 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
144 Test to see if this driver supports ControllerHandle. Any ControllerHandle
145 that has ExtScsiPassThruProtocol/ScsiPassThruProtocol installed will be supported.
149 This - Protocol instance pointer.
150 Controller - Handle of device to test
151 RemainingDevicePath - Not used
155 EFI_SUCCESS - This driver supports this device.
156 EFI_UNSUPPORTED - This driver does not support this device.
162 EFI_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
163 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtPassThru
;
165 // Check for the existence of Extended SCSI Pass Thru Protocol and SCSI Pass Thru Protocol
167 Status
= gBS
->OpenProtocol (
169 &gEfiExtScsiPassThruProtocolGuid
,
170 (VOID
**)&ExtPassThru
,
171 This
->DriverBindingHandle
,
173 EFI_OPEN_PROTOCOL_BY_DRIVER
176 if (Status
== EFI_ALREADY_STARTED
) {
180 if (EFI_ERROR (Status
)) {
181 Status
= gBS
->OpenProtocol (
183 &gEfiScsiPassThruProtocolGuid
,
185 This
->DriverBindingHandle
,
187 EFI_OPEN_PROTOCOL_BY_DRIVER
190 if (Status
== EFI_ALREADY_STARTED
) {
194 if (EFI_ERROR (Status
)) {
200 &gEfiScsiPassThruProtocolGuid
,
201 This
->DriverBindingHandle
,
209 &gEfiExtScsiPassThruProtocolGuid
,
210 This
->DriverBindingHandle
,
219 SCSIBusDriverBindingStart (
220 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
221 IN EFI_HANDLE Controller
,
222 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
227 Starting the SCSI Bus Driver
230 This - Protocol instance pointer.
231 Controller - Handle of device to test
232 RemainingDevicePath - Not used
235 EFI_SUCCESS - This driver supports this device.
236 EFI_UNSUPPORTED - This driver does not support this device.
237 EFI_DEVICE_ERROR - This driver cannot be started due to device Error
240 // TODO: This - add argument and description to function comment
241 // TODO: Controller - add argument and description to function comment
242 // TODO: RemainingDevicePath - add argument and description to function comment
246 BOOLEAN ScanOtherPuns
;
247 SCSI_BUS_DEVICE
*ScsiBusDev
;
248 BOOLEAN FromFirstTarget
;
249 SCSI_TARGET_ID
*ScsiTargetId
;
253 ScanOtherPuns
= TRUE
;
254 FromFirstTarget
= FALSE
;
256 // Allocate SCSI_BUS_DEVICE structure
259 ScsiBusDev
= AllocateZeroPool (sizeof (SCSI_BUS_DEVICE
));
260 if (ScsiBusDev
== NULL
) {
261 return EFI_OUT_OF_RESOURCES
;
265 ScsiTargetId
= AllocateZeroPool (sizeof (SCSI_TARGET_ID
));
266 if (ScsiTargetId
== NULL
) {
267 return EFI_OUT_OF_RESOURCES
;
270 TargetId
= &ScsiTargetId
->ScsiId
.ExtScsi
[0];
272 Status
= gBS
->OpenProtocol (
274 &gEfiDevicePathProtocolGuid
,
275 (VOID
**) &(ScsiBusDev
->DevicePath
),
276 This
->DriverBindingHandle
,
278 EFI_OPEN_PROTOCOL_BY_DRIVER
280 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
281 gBS
->FreePool (ScsiBusDev
);
286 // First consume Extended SCSI Pass Thru protocol, if fail, then consume
287 // SCSI Pass Thru protocol
289 Status
= gBS
->OpenProtocol (
291 &gEfiExtScsiPassThruProtocolGuid
,
292 (VOID
**) &(ScsiBusDev
->ExtScsiInterface
),
293 This
->DriverBindingHandle
,
295 EFI_OPEN_PROTOCOL_BY_DRIVER
297 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
298 Status
= gBS
->OpenProtocol (
300 &gEfiScsiPassThruProtocolGuid
,
301 (VOID
**) &(ScsiBusDev
->ScsiInterface
),
302 This
->DriverBindingHandle
,
304 EFI_OPEN_PROTOCOL_BY_DRIVER
306 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
309 &gEfiDevicePathProtocolGuid
,
310 This
->DriverBindingHandle
,
313 gBS
->FreePool (ScsiBusDev
);
316 DEBUG ((EFI_D_INFO
, "Open Scsi Pass Thrugh Protocol\n"));
317 ScsiBusDev
->ExtScsiSupport
= FALSE
;
319 DEBUG ((EFI_D_INFO
, "Open Extended Scsi Pass Thrugh Protocol\n"));
320 ScsiBusDev
->ExtScsiSupport
= TRUE
;
323 ScsiBusDev
->Signature
= SCSI_BUS_DEVICE_SIGNATURE
;
325 // Attach EFI_SCSI_BUS_PROTOCOL to controller handle
327 Status
= gBS
->InstallProtocolInterface (
329 &mScsiBusProtocolGuid
,
330 EFI_NATIVE_INTERFACE
,
331 &ScsiBusDev
->BusIdentify
334 if (EFI_ERROR (Status
)) {
337 &gEfiDevicePathProtocolGuid
,
338 This
->DriverBindingHandle
,
341 if (ScsiBusDev
->ExtScsiSupport
) {
344 &gEfiExtScsiPassThruProtocolGuid
,
345 This
->DriverBindingHandle
,
351 &gEfiScsiPassThruProtocolGuid
,
352 This
->DriverBindingHandle
,
356 gBS
->FreePool (ScsiBusDev
);
360 if (RemainingDevicePath
== NULL
) {
361 SetMem (ScsiTargetId
, TARGET_MAX_BYTES
,0xFF);
363 FromFirstTarget
= TRUE
;
365 if (ScsiBusDev
->ExtScsiSupport
) {
366 ScsiBusDev
->ExtScsiInterface
->GetTargetLun (ScsiBusDev
->ExtScsiInterface
, RemainingDevicePath
, &TargetId
, &Lun
);
368 ScsiBusDev
->ScsiInterface
->GetTargetLun (ScsiBusDev
->ScsiInterface
, RemainingDevicePath
, &ScsiTargetId
->ScsiId
.Scsi
, &Lun
);
372 while(ScanOtherPuns
) {
373 if (FromFirstTarget
) {
375 // Remaining Device Path is NULL, scan all the possible Puns in the
378 if (ScsiBusDev
->ExtScsiSupport
) {
379 Status
= ScsiBusDev
->ExtScsiInterface
->GetNextTargetLun (ScsiBusDev
->ExtScsiInterface
, &TargetId
, &Lun
);
381 Status
= ScsiBusDev
->ScsiInterface
->GetNextDevice (ScsiBusDev
->ScsiInterface
, &ScsiTargetId
->ScsiId
.Scsi
, &Lun
);
383 if (EFI_ERROR (Status
)) {
385 // no legal Pun and Lun found any more
390 ScanOtherPuns
= FALSE
;
393 // Avoid creating handle for the host adapter.
395 if (ScsiBusDev
->ExtScsiSupport
) {
396 if ((ScsiTargetId
->ScsiId
.Scsi
) == ScsiBusDev
->ExtScsiInterface
->Mode
->AdapterId
) {
400 if ((ScsiTargetId
->ScsiId
.Scsi
) == ScsiBusDev
->ScsiInterface
->Mode
->AdapterId
) {
405 // Scan for the scsi device, if it attaches to the scsi bus,
406 // then create handle and install scsi i/o protocol.
408 Status
= ScsiScanCreateDevice (This
, Controller
, ScsiTargetId
, Lun
, ScsiBusDev
);
415 SCSIBusDriverBindingStop (
416 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
417 IN EFI_HANDLE Controller
,
418 IN UINTN NumberOfChildren
,
419 IN EFI_HANDLE
*ChildHandleBuffer
430 // TODO: This - add argument and description to function comment
431 // TODO: Controller - add argument and description to function comment
432 // TODO: NumberOfChildren - add argument and description to function comment
433 // TODO: ChildHandleBuffer - add argument and description to function comment
434 // TODO: EFI_SUCCESS - add return value to function comment
435 // TODO: EFI_DEVICE_ERROR - add return value to function comment
436 // TODO: EFI_SUCCESS - add return value to function comment
439 BOOLEAN AllChildrenStopped
;
441 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
442 SCSI_IO_DEV
*ScsiIoDevice
;
444 EFI_SCSI_BUS_PROTOCOL
*Scsidentifier
;
445 SCSI_BUS_DEVICE
*ScsiBusDev
;
447 if (NumberOfChildren
== 0) {
449 // Get the SCSI_BUS_DEVICE
451 Status
= gBS
->OpenProtocol (
453 &mScsiBusProtocolGuid
,
454 (VOID
**) &Scsidentifier
,
455 This
->DriverBindingHandle
,
457 EFI_OPEN_PROTOCOL_GET_PROTOCOL
460 if (EFI_ERROR (Status
)) {
461 return EFI_DEVICE_ERROR
;
464 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier
);
467 // Uninstall SCSI Bus Protocol
469 gBS
->UninstallProtocolInterface (
471 &mScsiBusProtocolGuid
,
472 &ScsiBusDev
->BusIdentify
476 // Close the bus driver
478 if (ScsiBusDev
->ExtScsiSupport
) {
481 &gEfiExtScsiPassThruProtocolGuid
,
482 This
->DriverBindingHandle
,
488 &gEfiScsiPassThruProtocolGuid
,
489 This
->DriverBindingHandle
,
496 &gEfiDevicePathProtocolGuid
,
497 This
->DriverBindingHandle
,
500 gBS
->FreePool (ScsiBusDev
);
504 AllChildrenStopped
= TRUE
;
506 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
508 Status
= gBS
->OpenProtocol (
509 ChildHandleBuffer
[Index
],
510 &gEfiScsiIoProtocolGuid
,
512 This
->DriverBindingHandle
,
514 EFI_OPEN_PROTOCOL_GET_PROTOCOL
516 if (EFI_ERROR (Status
)) {
517 AllChildrenStopped
= FALSE
;
521 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (ScsiIo
);
523 // Close the child handle
525 if (ScsiIoDevice
->ExtScsiSupport
) {
526 Status
= gBS
->CloseProtocol (
528 &gEfiExtScsiPassThruProtocolGuid
,
529 This
->DriverBindingHandle
,
530 ChildHandleBuffer
[Index
]
534 Status
= gBS
->CloseProtocol (
536 &gEfiScsiPassThruProtocolGuid
,
537 This
->DriverBindingHandle
,
538 ChildHandleBuffer
[Index
]
542 Status
= gBS
->UninstallMultipleProtocolInterfaces (
543 ChildHandleBuffer
[Index
],
544 &gEfiDevicePathProtocolGuid
,
545 ScsiIoDevice
->DevicePath
,
546 &gEfiScsiIoProtocolGuid
,
547 &ScsiIoDevice
->ScsiIo
,
550 if (EFI_ERROR (Status
)) {
551 AllChildrenStopped
= FALSE
;
552 if (ScsiIoDevice
->ExtScsiSupport
) {
555 &gEfiExtScsiPassThruProtocolGuid
,
556 &(EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)ScsiPassThru
,
557 This
->DriverBindingHandle
,
558 ChildHandleBuffer
[Index
],
559 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
564 &gEfiScsiPassThruProtocolGuid
,
565 &(EFI_SCSI_PASS_THRU_PROTOCOL
*)ScsiPassThru
,
566 This
->DriverBindingHandle
,
567 ChildHandleBuffer
[Index
],
568 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
572 gBS
->FreePool (ScsiIoDevice
);
576 if (!AllChildrenStopped
) {
577 return EFI_DEVICE_ERROR
;
586 IN EFI_SCSI_IO_PROTOCOL
*This
,
587 OUT UINT8
*DeviceType
592 Retrieves the device type information of the SCSI Controller.
595 This - Protocol instance pointer.
596 DeviceType - A pointer to the device type information
597 retrieved from the SCSI Controller.
600 EFI_SUCCESS - Retrieves the device type information successfully.
601 EFI_INVALID_PARAMETER - The DeviceType is NULL.
604 SCSI_IO_DEV
*ScsiIoDevice
;
606 if (DeviceType
== NULL
) {
607 return EFI_INVALID_PARAMETER
;
610 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
611 *DeviceType
= ScsiIoDevice
->ScsiDeviceType
;
617 ScsiGetDeviceLocation (
618 IN EFI_SCSI_IO_PROTOCOL
*This
,
619 IN OUT UINT8
**Target
,
624 Retrieves the device location in the SCSI channel.
627 This - Protocol instance pointer.
628 Target - A pointer to the Target ID of a SCSI device
630 Lun - A pointer to the LUN of the SCSI device on
634 EFI_SUCCESS - Retrieves the device location successfully.
635 EFI_INVALID_PARAMETER - The Target or Lun is NULL.
638 SCSI_IO_DEV
*ScsiIoDevice
;
640 if (Target
== NULL
|| Lun
== NULL
) {
641 return EFI_INVALID_PARAMETER
;
644 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
646 CopyMem (*Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
648 *Lun
= ScsiIoDevice
->Lun
;
656 IN EFI_SCSI_IO_PROTOCOL
*This
661 Resets the SCSI Bus that the SCSI Controller is attached to.
664 This - Protocol instance pointer.
667 EFI_SUCCESS - The SCSI bus is reset successfully.
668 EFI_DEVICE_ERROR - Errors encountered when resetting the SCSI bus.
669 EFI_UNSUPPORTED - The bus reset operation is not supported by the
670 SCSI Host Controller.
671 EFI_TIMEOUT - A timeout occurred while attempting to reset
675 SCSI_IO_DEV
*ScsiIoDevice
;
677 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
679 if (ScsiIoDevice
->ExtScsiSupport
){
680 return ScsiIoDevice
->ExtScsiPassThru
->ResetChannel (ScsiIoDevice
->ExtScsiPassThru
);
682 return ScsiIoDevice
->ScsiPassThru
->ResetChannel (ScsiIoDevice
->ScsiPassThru
);
689 IN EFI_SCSI_IO_PROTOCOL
*This
694 Resets the SCSI Controller that the device handle specifies.
697 This - Protocol instance pointer.
701 EFI_SUCCESS - Reset the SCSI controller successfully.
702 EFI_DEVICE_ERROR - Errors are encountered when resetting the
704 EFI_UNSUPPORTED - The SCSI bus does not support a device
706 EFI_TIMEOUT - A timeout occurred while attempting to
707 reset the SCSI Controller.
710 SCSI_IO_DEV
*ScsiIoDevice
;
711 UINT8 Target
[TARGET_MAX_BYTES
];
713 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
714 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
717 if (ScsiIoDevice
->ExtScsiSupport
) {
718 return ScsiIoDevice
->ExtScsiPassThru
->ResetTargetLun (
719 ScsiIoDevice
->ExtScsiPassThru
,
724 return ScsiIoDevice
->ScsiPassThru
->ResetTarget (
725 ScsiIoDevice
->ScsiPassThru
,
726 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
734 ScsiExecuteSCSICommand (
735 IN EFI_SCSI_IO_PROTOCOL
*This
,
736 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
737 IN EFI_EVENT Event OPTIONAL
742 Sends a SCSI Request Packet to the SCSI Controller for execution.
745 This - Protocol instance pointer.
746 Packet - The SCSI request packet to send to the SCSI
747 Controller specified by the device handle.
748 Event - If the SCSI bus where the SCSI device is attached
749 does not support non-blocking I/O, then Event is
750 ignored, and blocking I/O is performed.
751 If Event is NULL, then blocking I/O is performed.
752 If Event is not NULL and non-blocking I/O is
753 supported, then non-blocking I/O is performed,
754 and Event will be signaled when the SCSI Request
757 EFI_SUCCESS - The SCSI Request Packet was sent by the host
758 successfully, and TransferLength bytes were
759 transferred to/from DataBuffer.See
760 HostAdapterStatus, TargetStatus,
761 SenseDataLength, and SenseData in that order
762 for additional status information.
763 EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed,
764 but the entire DataBuffer could not be transferred.
765 The actual number of bytes transferred is returned
766 in TransferLength. See HostAdapterStatus,
767 TargetStatus, SenseDataLength, and SenseData in
768 that order for additional status information.
769 EFI_NOT_READY - The SCSI Request Packet could not be sent because
770 there are too many SCSI Command Packets already
771 queued.The caller may retry again later.
772 EFI_DEVICE_ERROR - A device error occurred while attempting to send
773 the SCSI Request Packet. See HostAdapterStatus,
774 TargetStatus, SenseDataLength, and SenseData in
775 that order for additional status information.
776 EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid.
777 The SCSI Request Packet was not sent, so no
778 additional status information is available.
779 EFI_UNSUPPORTED - The command described by the SCSI Request Packet
780 is not supported by the SCSI initiator(i.e., SCSI
781 Host Controller). The SCSI Request Packet was not
782 sent, so no additional status information is
784 EFI_TIMEOUT - A timeout occurred while waiting for the SCSI
785 Request Packet to execute. See HostAdapterStatus,
786 TargetStatus, SenseDataLength, and SenseData in
787 that order for additional status information.
790 SCSI_IO_DEV
*ScsiIoDevice
;
792 UINT8 Target
[TARGET_MAX_BYTES
];
793 EFI_EVENT PacketEvent
;
794 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ExtRequestPacket
;
795 SCSI_EVENT_DATA EventData
;
799 if (Packet
== NULL
) {
800 return EFI_INVALID_PARAMETER
;
803 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
804 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
806 if (ScsiIoDevice
->ExtScsiSupport
) {
807 ExtRequestPacket
= (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*) Packet
;
808 Status
= ScsiIoDevice
->ExtScsiPassThru
->PassThru (
809 ScsiIoDevice
->ExtScsiPassThru
,
817 Status
= gBS
->AllocatePool (
819 sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
),
820 (VOID
**)&WorkingBuffer
823 if (EFI_ERROR (Status
)) {
824 return EFI_DEVICE_ERROR
;
828 // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.
830 Status
= ScsiioToPassThruPacket(Packet
, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
);
831 if (EFI_ERROR(Status
)) {
832 gBS
->FreePool(WorkingBuffer
);
836 if ((ScsiIoDevice
->ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO
) && (Event
!= NULL
)) {
837 EventData
.Data1
= (VOID
*)Packet
;
838 EventData
.Data2
= Event
;
842 Status
= gBS
->CreateEvent (
849 if (EFI_ERROR(Status
)) {
850 gBS
->FreePool(WorkingBuffer
);
854 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
855 ScsiIoDevice
->ScsiPassThru
,
856 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
862 if (EFI_ERROR(Status
)) {
863 gBS
->FreePool(WorkingBuffer
);
864 gBS
->CloseEvent(PacketEvent
);
870 // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert
871 // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.
873 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
874 ScsiIoDevice
->ScsiPassThru
,
875 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
880 if (EFI_ERROR(Status
)) {
881 gBS
->FreePool(WorkingBuffer
);
885 PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
,Packet
);
887 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
888 // free WorkingBuffer.
890 gBS
->FreePool(WorkingBuffer
);
898 ScsiScanCreateDevice (
899 EFI_DRIVER_BINDING_PROTOCOL
*This
,
900 EFI_HANDLE Controller
,
901 SCSI_TARGET_ID
*TargetId
,
903 SCSI_BUS_DEVICE
*ScsiBusDev
909 Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.
913 This - Protocol instance pointer
914 Controller - Controller handle
915 Pun - The Pun of the SCSI device on the SCSI channel.
916 Lun - The Lun of the SCSI device on the SCSI channel.
917 ScsiBusDev - The pointer of SCSI_BUS_DEVICE
921 EFI_SUCCESS - Successfully to discover the device and attach ScsiIoProtocol to it.
922 EFI_OUT_OF_RESOURCES - Fail to discover the device.
927 SCSI_IO_DEV
*ScsiIoDevice
;
928 EFI_DEVICE_PATH_PROTOCOL
*ScsiDevicePath
;
930 Status
= gBS
->AllocatePool (
932 sizeof (SCSI_IO_DEV
),
933 (VOID
**) &ScsiIoDevice
935 if (EFI_ERROR (Status
)) {
939 ZeroMem (ScsiIoDevice
, sizeof (SCSI_IO_DEV
));
941 ScsiIoDevice
->Signature
= SCSI_IO_DEV_SIGNATURE
;
942 CopyMem(&ScsiIoDevice
->Pun
, TargetId
, TARGET_MAX_BYTES
);
943 ScsiIoDevice
->Lun
= Lun
;
945 if (ScsiBusDev
->ExtScsiSupport
) {
946 ScsiIoDevice
->ExtScsiPassThru
= ScsiBusDev
->ExtScsiInterface
;
947 ScsiIoDevice
->ExtScsiSupport
= TRUE
;
948 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ExtScsiPassThru
->Mode
->IoAlign
;
951 ScsiIoDevice
->ScsiPassThru
= ScsiBusDev
->ScsiInterface
;
952 ScsiIoDevice
->ExtScsiSupport
= FALSE
;
953 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ScsiPassThru
->Mode
->IoAlign
;
956 ScsiIoDevice
->ScsiIo
.GetDeviceType
= ScsiGetDeviceType
;
957 ScsiIoDevice
->ScsiIo
.GetDeviceLocation
= ScsiGetDeviceLocation
;
958 ScsiIoDevice
->ScsiIo
.ResetBus
= ScsiResetBus
;
959 ScsiIoDevice
->ScsiIo
.ResetDevice
= ScsiResetDevice
;
960 ScsiIoDevice
->ScsiIo
.ExecuteScsiCommand
= ScsiExecuteSCSICommand
;
963 if (!DiscoverScsiDevice (ScsiIoDevice
)) {
964 gBS
->FreePool (ScsiIoDevice
);
965 return EFI_OUT_OF_RESOURCES
;
971 if (ScsiIoDevice
->ExtScsiSupport
){
972 Status
= ScsiIoDevice
->ExtScsiPassThru
->BuildDevicePath (
973 ScsiIoDevice
->ExtScsiPassThru
,
974 &ScsiIoDevice
->Pun
.ScsiId
.ExtScsi
[0],
978 if (Status
== EFI_OUT_OF_RESOURCES
) {
979 gBS
->FreePool (ScsiIoDevice
);
983 Status
= ScsiIoDevice
->ScsiPassThru
->BuildDevicePath (
984 ScsiIoDevice
->ScsiPassThru
,
985 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
989 if (Status
== EFI_OUT_OF_RESOURCES
) {
990 gBS
->FreePool (ScsiIoDevice
);
995 ScsiIoDevice
->DevicePath
= AppendDevicePathNode (
996 ScsiBusDev
->DevicePath
,
1000 // The memory space for ScsiDevicePath is allocated in
1001 // ScsiPassThru->BuildDevicePath() function; It is no longer used
1002 // after EfiAppendDevicePathNode,so free the memory it occupies.
1004 gBS
->FreePool (ScsiDevicePath
);
1006 if (ScsiIoDevice
->DevicePath
== NULL
) {
1007 gBS
->FreePool (ScsiIoDevice
);
1008 return EFI_OUT_OF_RESOURCES
;
1011 Status
= gBS
->InstallMultipleProtocolInterfaces (
1012 &ScsiIoDevice
->Handle
,
1013 &gEfiDevicePathProtocolGuid
,
1014 ScsiIoDevice
->DevicePath
,
1015 &gEfiScsiIoProtocolGuid
,
1016 &ScsiIoDevice
->ScsiIo
,
1019 if (EFI_ERROR (Status
)) {
1020 gBS
->FreePool (ScsiIoDevice
);
1021 return EFI_OUT_OF_RESOURCES
;
1023 if (ScsiBusDev
->ExtScsiSupport
) {
1026 &gEfiExtScsiPassThruProtocolGuid
,
1027 (VOID
**) &(ScsiBusDev
->ExtScsiInterface
),
1028 This
->DriverBindingHandle
,
1029 ScsiIoDevice
->Handle
,
1030 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1035 &gEfiScsiPassThruProtocolGuid
,
1036 (VOID
**) &(ScsiBusDev
->ScsiInterface
),
1037 This
->DriverBindingHandle
,
1038 ScsiIoDevice
->Handle
,
1039 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1048 DiscoverScsiDevice (
1049 SCSI_IO_DEV
*ScsiIoDevice
1053 Routine Description:
1055 Discovery SCSI Device
1059 ScsiIoDevice - The pointer of SCSI_IO_DEV
1063 TRUE - Find SCSI Device and verify it.
1064 FALSE - Unable to find SCSI Device.
1069 UINT32 InquiryDataLength
;
1070 UINT8 SenseDataLength
;
1071 UINT8 HostAdapterStatus
;
1073 EFI_SCSI_SENSE_DATA SenseData
;
1074 EFI_SCSI_INQUIRY_DATA InquiryData
;
1076 HostAdapterStatus
= 0;
1079 // Using Inquiry command to scan for the device
1081 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1082 SenseDataLength
= sizeof (EFI_SCSI_SENSE_DATA
);
1084 Status
= SubmitInquiryCommand (
1085 &ScsiIoDevice
->ScsiIo
,
1086 EfiScsiStallSeconds (1),
1087 (VOID
*) &SenseData
,
1091 (VOID
*) &InquiryData
,
1095 if (EFI_ERROR (Status
)) {
1097 // ParseSenseData (&SenseData,SenseDataLength);
1102 // Retrieved inquiry data successfully
1104 if ((InquiryData
.Peripheral_Qualifier
!= 0) &&
1105 (InquiryData
.Peripheral_Qualifier
!= 3)) {
1109 if (InquiryData
.Peripheral_Qualifier
== 3) {
1110 if (InquiryData
.Peripheral_Type
!= 0x1f) {
1115 if (0x1e >= InquiryData
.Peripheral_Type
>= 0xa) {
1120 // valid device type and peripheral qualifier combination.
1122 ScsiIoDevice
->ScsiDeviceType
= InquiryData
.Peripheral_Type
;
1123 ScsiIoDevice
->RemovableDevice
= InquiryData
.RMB
;
1124 if (InquiryData
.Version
== 0) {
1125 ScsiIoDevice
->ScsiVersion
= 0;
1128 // ANSI-approved version
1130 ScsiIoDevice
->ScsiVersion
= (UINT8
) (InquiryData
.Version
& 0x03);
1140 ScsiioToPassThruPacket (
1141 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
1142 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
1146 Routine Description:
1148 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to
1149 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet
1153 Packet - The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1154 CommandPacket - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1163 //EFI 1.10 doesn't support Bi-Direction Command.
1165 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL
) {
1166 return EFI_UNSUPPORTED
;
1169 ZeroMem (CommandPacket
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1171 CommandPacket
->Timeout
= Packet
->Timeout
;
1172 CommandPacket
->Cdb
= Packet
->Cdb
;
1173 CommandPacket
->CdbLength
= Packet
->CdbLength
;
1174 CommandPacket
->DataDirection
= Packet
->DataDirection
;
1175 CommandPacket
->HostAdapterStatus
= Packet
->HostAdapterStatus
;
1176 CommandPacket
->TargetStatus
= Packet
->TargetStatus
;
1177 CommandPacket
->SenseData
= Packet
->SenseData
;
1178 CommandPacket
->SenseDataLength
= Packet
->SenseDataLength
;
1180 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1181 CommandPacket
->DataBuffer
= Packet
->InDataBuffer
;
1182 CommandPacket
->TransferLength
= Packet
->InTransferLength
;
1183 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1184 CommandPacket
->DataBuffer
= Packet
->OutDataBuffer
;
1185 CommandPacket
->TransferLength
= Packet
->OutTransferLength
;
1194 PassThruToScsiioPacket (
1195 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
1196 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
1200 Routine Description:
1202 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to
1203 EFI_SCSI_IO_SCSI_REQUEST_PACKET packet
1207 ScsiPacket - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1208 Packet - The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1216 Packet
->Timeout
= ScsiPacket
->Timeout
;
1217 Packet
->Cdb
= ScsiPacket
->Cdb
;
1218 Packet
->CdbLength
= ScsiPacket
->CdbLength
;
1219 Packet
->DataDirection
= ScsiPacket
->DataDirection
;
1220 Packet
->HostAdapterStatus
= ScsiPacket
->HostAdapterStatus
;
1221 Packet
->TargetStatus
= ScsiPacket
->TargetStatus
;
1222 Packet
->SenseData
= ScsiPacket
->SenseData
;
1223 Packet
->SenseDataLength
= ScsiPacket
->SenseDataLength
;
1225 if (ScsiPacket
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1226 Packet
->InDataBuffer
= ScsiPacket
->DataBuffer
;
1227 Packet
->InTransferLength
= ScsiPacket
->TransferLength
;
1228 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1229 Packet
->OutDataBuffer
= ScsiPacket
->DataBuffer
;
1230 Packet
->OutTransferLength
= ScsiPacket
->TransferLength
;
1247 Routine Description:
1249 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
1254 Event - The instance of EFI_EVENT.
1255 Context - The parameter passed in.
1263 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
;
1264 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
;
1265 EFI_EVENT CallerEvent
;
1266 SCSI_EVENT_DATA
*PassData
;
1268 PassData
= (SCSI_EVENT_DATA
*)Context
;
1269 Packet
= (EFI_SCSI_IO_SCSI_REQUEST_PACKET
*)PassData
->Data1
;
1270 ScsiPacket
= (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
;
1273 // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.
1275 PassThruToScsiioPacket(ScsiPacket
, Packet
);
1278 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1279 // free WorkingBuffer.
1281 gBS
->FreePool(WorkingBuffer
);
1284 // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.
1286 CallerEvent
= PassData
->Data2
;
1287 gBS
->CloseEvent(Event
);
1288 gBS
->SignalEvent(CallerEvent
);