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
);
129 SCSIBusDriverBindingSupported (
130 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
131 IN EFI_HANDLE Controller
,
132 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
138 Test to see if this driver supports ControllerHandle. Any ControllerHandle
139 that has ExtScsiPassThruProtocol/ScsiPassThruProtocol installed will be supported.
143 This - Protocol instance pointer.
144 Controller - Handle of device to test
145 RemainingDevicePath - Not used
149 EFI_SUCCESS - This driver supports this device.
150 EFI_UNSUPPORTED - This driver does not support this device.
156 EFI_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
157 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtPassThru
;
159 // Check for the existence of Extended SCSI Pass Thru Protocol and SCSI Pass Thru Protocol
161 Status
= gBS
->OpenProtocol (
163 &gEfiExtScsiPassThruProtocolGuid
,
164 (VOID
**)&ExtPassThru
,
165 This
->DriverBindingHandle
,
167 EFI_OPEN_PROTOCOL_BY_DRIVER
170 if (Status
== EFI_ALREADY_STARTED
) {
174 if (EFI_ERROR (Status
)) {
175 Status
= gBS
->OpenProtocol (
177 &gEfiScsiPassThruProtocolGuid
,
179 This
->DriverBindingHandle
,
181 EFI_OPEN_PROTOCOL_BY_DRIVER
184 if (Status
== EFI_ALREADY_STARTED
) {
188 if (EFI_ERROR (Status
)) {
194 &gEfiScsiPassThruProtocolGuid
,
195 This
->DriverBindingHandle
,
203 &gEfiExtScsiPassThruProtocolGuid
,
204 This
->DriverBindingHandle
,
213 SCSIBusDriverBindingStart (
214 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
215 IN EFI_HANDLE Controller
,
216 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
221 Starting the SCSI Bus Driver
224 This - Protocol instance pointer.
225 Controller - Handle of device to test
226 RemainingDevicePath - Not used
229 EFI_SUCCESS - This driver supports this device.
230 EFI_UNSUPPORTED - This driver does not support this device.
231 EFI_DEVICE_ERROR - This driver cannot be started due to device Error
234 // TODO: This - add argument and description to function comment
235 // TODO: Controller - add argument and description to function comment
236 // TODO: RemainingDevicePath - add argument and description to function comment
240 BOOLEAN ScanOtherPuns
;
241 SCSI_BUS_DEVICE
*ScsiBusDev
;
242 BOOLEAN FromFirstTarget
;
243 SCSI_TARGET_ID
*ScsiTargetId
;
247 ScanOtherPuns
= TRUE
;
248 FromFirstTarget
= FALSE
;
250 // Allocate SCSI_BUS_DEVICE structure
253 ScsiBusDev
= AllocateZeroPool (sizeof (SCSI_BUS_DEVICE
));
254 if (ScsiBusDev
== NULL
) {
255 return EFI_OUT_OF_RESOURCES
;
259 ScsiTargetId
= AllocateZeroPool (sizeof (SCSI_TARGET_ID
));
260 if (ScsiTargetId
== NULL
) {
261 return EFI_OUT_OF_RESOURCES
;
264 TargetId
= &ScsiTargetId
->ScsiId
.ExtScsi
[0];
266 Status
= gBS
->OpenProtocol (
268 &gEfiDevicePathProtocolGuid
,
269 (VOID
**) &(ScsiBusDev
->DevicePath
),
270 This
->DriverBindingHandle
,
272 EFI_OPEN_PROTOCOL_BY_DRIVER
274 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
275 gBS
->FreePool (ScsiBusDev
);
280 // First consume Extended SCSI Pass Thru protocol, if fail, then consume
281 // SCSI Pass Thru protocol
283 Status
= gBS
->OpenProtocol (
285 &gEfiExtScsiPassThruProtocolGuid
,
286 (VOID
**) &(ScsiBusDev
->ExtScsiInterface
),
287 This
->DriverBindingHandle
,
289 EFI_OPEN_PROTOCOL_BY_DRIVER
291 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
292 Status
= gBS
->OpenProtocol (
294 &gEfiScsiPassThruProtocolGuid
,
295 (VOID
**) &(ScsiBusDev
->ScsiInterface
),
296 This
->DriverBindingHandle
,
298 EFI_OPEN_PROTOCOL_BY_DRIVER
300 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
303 &gEfiDevicePathProtocolGuid
,
304 This
->DriverBindingHandle
,
307 gBS
->FreePool (ScsiBusDev
);
310 DEBUG ((EFI_D_INFO
, "Open Scsi Pass Thrugh Protocol\n"));
311 ScsiBusDev
->ExtScsiSupport
= FALSE
;
313 DEBUG ((EFI_D_INFO
, "Open Extended Scsi Pass Thrugh Protocol\n"));
314 ScsiBusDev
->ExtScsiSupport
= TRUE
;
317 ScsiBusDev
->Signature
= SCSI_BUS_DEVICE_SIGNATURE
;
319 // Attach EFI_SCSI_BUS_PROTOCOL to controller handle
321 Status
= gBS
->InstallProtocolInterface (
323 &mScsiBusProtocolGuid
,
324 EFI_NATIVE_INTERFACE
,
325 &ScsiBusDev
->BusIdentify
328 if (EFI_ERROR (Status
)) {
331 &gEfiDevicePathProtocolGuid
,
332 This
->DriverBindingHandle
,
335 if (ScsiBusDev
->ExtScsiSupport
) {
338 &gEfiExtScsiPassThruProtocolGuid
,
339 This
->DriverBindingHandle
,
345 &gEfiScsiPassThruProtocolGuid
,
346 This
->DriverBindingHandle
,
350 gBS
->FreePool (ScsiBusDev
);
354 if (RemainingDevicePath
== NULL
) {
355 SetMem (ScsiTargetId
, TARGET_MAX_BYTES
,0xFF);
357 FromFirstTarget
= TRUE
;
359 if (ScsiBusDev
->ExtScsiSupport
) {
360 ScsiBusDev
->ExtScsiInterface
->GetTargetLun (ScsiBusDev
->ExtScsiInterface
, RemainingDevicePath
, &TargetId
, &Lun
);
362 ScsiBusDev
->ScsiInterface
->GetTargetLun (ScsiBusDev
->ScsiInterface
, RemainingDevicePath
, &ScsiTargetId
->ScsiId
.Scsi
, &Lun
);
366 while(ScanOtherPuns
) {
367 if (FromFirstTarget
) {
369 // Remaining Device Path is NULL, scan all the possible Puns in the
372 if (ScsiBusDev
->ExtScsiSupport
) {
373 Status
= ScsiBusDev
->ExtScsiInterface
->GetNextTargetLun (ScsiBusDev
->ExtScsiInterface
, &TargetId
, &Lun
);
375 Status
= ScsiBusDev
->ScsiInterface
->GetNextDevice (ScsiBusDev
->ScsiInterface
, &ScsiTargetId
->ScsiId
.Scsi
, &Lun
);
377 if (EFI_ERROR (Status
)) {
379 // no legal Pun and Lun found any more
384 ScanOtherPuns
= FALSE
;
387 // Avoid creating handle for the host adapter.
389 if (ScsiBusDev
->ExtScsiSupport
) {
390 if ((ScsiTargetId
->ScsiId
.Scsi
) == ScsiBusDev
->ExtScsiInterface
->Mode
->AdapterId
) {
394 if ((ScsiTargetId
->ScsiId
.Scsi
) == ScsiBusDev
->ScsiInterface
->Mode
->AdapterId
) {
399 // Scan for the scsi device, if it attaches to the scsi bus,
400 // then create handle and install scsi i/o protocol.
402 Status
= ScsiScanCreateDevice (This
, Controller
, ScsiTargetId
, Lun
, ScsiBusDev
);
409 SCSIBusDriverBindingStop (
410 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
411 IN EFI_HANDLE Controller
,
412 IN UINTN NumberOfChildren
,
413 IN EFI_HANDLE
*ChildHandleBuffer
424 // TODO: This - add argument and description to function comment
425 // TODO: Controller - add argument and description to function comment
426 // TODO: NumberOfChildren - add argument and description to function comment
427 // TODO: ChildHandleBuffer - add argument and description to function comment
428 // TODO: EFI_SUCCESS - add return value to function comment
429 // TODO: EFI_DEVICE_ERROR - add return value to function comment
430 // TODO: EFI_SUCCESS - add return value to function comment
433 BOOLEAN AllChildrenStopped
;
435 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
436 SCSI_IO_DEV
*ScsiIoDevice
;
438 EFI_SCSI_BUS_PROTOCOL
*Scsidentifier
;
439 SCSI_BUS_DEVICE
*ScsiBusDev
;
441 if (NumberOfChildren
== 0) {
443 // Get the SCSI_BUS_DEVICE
445 Status
= gBS
->OpenProtocol (
447 &mScsiBusProtocolGuid
,
448 (VOID
**) &Scsidentifier
,
449 This
->DriverBindingHandle
,
451 EFI_OPEN_PROTOCOL_GET_PROTOCOL
454 if (EFI_ERROR (Status
)) {
455 return EFI_DEVICE_ERROR
;
458 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier
);
461 // Uninstall SCSI Bus Protocol
463 gBS
->UninstallProtocolInterface (
465 &mScsiBusProtocolGuid
,
466 &ScsiBusDev
->BusIdentify
470 // Close the bus driver
472 if (ScsiBusDev
->ExtScsiSupport
) {
475 &gEfiExtScsiPassThruProtocolGuid
,
476 This
->DriverBindingHandle
,
482 &gEfiScsiPassThruProtocolGuid
,
483 This
->DriverBindingHandle
,
490 &gEfiDevicePathProtocolGuid
,
491 This
->DriverBindingHandle
,
494 gBS
->FreePool (ScsiBusDev
);
498 AllChildrenStopped
= TRUE
;
500 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
502 Status
= gBS
->OpenProtocol (
503 ChildHandleBuffer
[Index
],
504 &gEfiScsiIoProtocolGuid
,
506 This
->DriverBindingHandle
,
508 EFI_OPEN_PROTOCOL_GET_PROTOCOL
510 if (EFI_ERROR (Status
)) {
511 AllChildrenStopped
= FALSE
;
515 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (ScsiIo
);
517 // Close the child handle
519 if (ScsiIoDevice
->ExtScsiSupport
) {
520 Status
= gBS
->CloseProtocol (
522 &gEfiExtScsiPassThruProtocolGuid
,
523 This
->DriverBindingHandle
,
524 ChildHandleBuffer
[Index
]
528 Status
= gBS
->CloseProtocol (
530 &gEfiScsiPassThruProtocolGuid
,
531 This
->DriverBindingHandle
,
532 ChildHandleBuffer
[Index
]
536 Status
= gBS
->UninstallMultipleProtocolInterfaces (
537 ChildHandleBuffer
[Index
],
538 &gEfiDevicePathProtocolGuid
,
539 ScsiIoDevice
->DevicePath
,
540 &gEfiScsiIoProtocolGuid
,
541 &ScsiIoDevice
->ScsiIo
,
544 if (EFI_ERROR (Status
)) {
545 AllChildrenStopped
= FALSE
;
546 if (ScsiIoDevice
->ExtScsiSupport
) {
549 &gEfiExtScsiPassThruProtocolGuid
,
550 (VOID
**) &(EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)ScsiPassThru
,
551 This
->DriverBindingHandle
,
552 ChildHandleBuffer
[Index
],
553 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
558 &gEfiScsiPassThruProtocolGuid
,
559 (VOID
**) &(EFI_SCSI_PASS_THRU_PROTOCOL
*)ScsiPassThru
,
560 This
->DriverBindingHandle
,
561 ChildHandleBuffer
[Index
],
562 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
566 gBS
->FreePool (ScsiIoDevice
);
570 if (!AllChildrenStopped
) {
571 return EFI_DEVICE_ERROR
;
580 IN EFI_SCSI_IO_PROTOCOL
*This
,
581 OUT UINT8
*DeviceType
586 Retrieves the device type information of the SCSI Controller.
589 This - Protocol instance pointer.
590 DeviceType - A pointer to the device type information
591 retrieved from the SCSI Controller.
594 EFI_SUCCESS - Retrieves the device type information successfully.
595 EFI_INVALID_PARAMETER - The DeviceType is NULL.
598 SCSI_IO_DEV
*ScsiIoDevice
;
600 if (DeviceType
== NULL
) {
601 return EFI_INVALID_PARAMETER
;
604 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
605 *DeviceType
= ScsiIoDevice
->ScsiDeviceType
;
611 ScsiGetDeviceLocation (
612 IN EFI_SCSI_IO_PROTOCOL
*This
,
613 IN OUT UINT8
**Target
,
618 Retrieves the device location in the SCSI channel.
621 This - Protocol instance pointer.
622 Target - A pointer to the Target ID of a SCSI device
624 Lun - A pointer to the LUN of the SCSI device on
628 EFI_SUCCESS - Retrieves the device location successfully.
629 EFI_INVALID_PARAMETER - The Target or Lun is NULL.
632 SCSI_IO_DEV
*ScsiIoDevice
;
634 if (Target
== NULL
|| Lun
== NULL
) {
635 return EFI_INVALID_PARAMETER
;
638 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
640 CopyMem (*Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
642 *Lun
= ScsiIoDevice
->Lun
;
650 IN EFI_SCSI_IO_PROTOCOL
*This
655 Resets the SCSI Bus that the SCSI Controller is attached to.
658 This - Protocol instance pointer.
661 EFI_SUCCESS - The SCSI bus is reset successfully.
662 EFI_DEVICE_ERROR - Errors encountered when resetting the SCSI bus.
663 EFI_UNSUPPORTED - The bus reset operation is not supported by the
664 SCSI Host Controller.
665 EFI_TIMEOUT - A timeout occurred while attempting to reset
669 SCSI_IO_DEV
*ScsiIoDevice
;
671 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
673 if (ScsiIoDevice
->ExtScsiSupport
){
674 return ScsiIoDevice
->ExtScsiPassThru
->ResetChannel (ScsiIoDevice
->ExtScsiPassThru
);
676 return ScsiIoDevice
->ScsiPassThru
->ResetChannel (ScsiIoDevice
->ScsiPassThru
);
683 IN EFI_SCSI_IO_PROTOCOL
*This
688 Resets the SCSI Controller that the device handle specifies.
691 This - Protocol instance pointer.
695 EFI_SUCCESS - Reset the SCSI controller successfully.
696 EFI_DEVICE_ERROR - Errors are encountered when resetting the
698 EFI_UNSUPPORTED - The SCSI bus does not support a device
700 EFI_TIMEOUT - A timeout occurred while attempting to
701 reset the SCSI Controller.
704 SCSI_IO_DEV
*ScsiIoDevice
;
705 UINT8 Target
[TARGET_MAX_BYTES
];
707 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
708 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
711 if (ScsiIoDevice
->ExtScsiSupport
) {
712 return ScsiIoDevice
->ExtScsiPassThru
->ResetTargetLun (
713 ScsiIoDevice
->ExtScsiPassThru
,
718 return ScsiIoDevice
->ScsiPassThru
->ResetTarget (
719 ScsiIoDevice
->ScsiPassThru
,
720 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
728 ScsiExecuteSCSICommand (
729 IN EFI_SCSI_IO_PROTOCOL
*This
,
730 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
731 IN EFI_EVENT Event OPTIONAL
736 Sends a SCSI Request Packet to the SCSI Controller for execution.
739 This - Protocol instance pointer.
740 Packet - The SCSI request packet to send to the SCSI
741 Controller specified by the device handle.
742 Event - If the SCSI bus where the SCSI device is attached
743 does not support non-blocking I/O, then Event is
744 ignored, and blocking I/O is performed.
745 If Event is NULL, then blocking I/O is performed.
746 If Event is not NULL and non-blocking I/O is
747 supported, then non-blocking I/O is performed,
748 and Event will be signaled when the SCSI Request
751 EFI_SUCCESS - The SCSI Request Packet was sent by the host
752 successfully, and TransferLength bytes were
753 transferred to/from DataBuffer.See
754 HostAdapterStatus, TargetStatus,
755 SenseDataLength, and SenseData in that order
756 for additional status information.
757 EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed,
758 but the entire DataBuffer could not be transferred.
759 The actual number of bytes transferred is returned
760 in TransferLength. See HostAdapterStatus,
761 TargetStatus, SenseDataLength, and SenseData in
762 that order for additional status information.
763 EFI_NOT_READY - The SCSI Request Packet could not be sent because
764 there are too many SCSI Command Packets already
765 queued.The caller may retry again later.
766 EFI_DEVICE_ERROR - A device error occurred while attempting to send
767 the SCSI Request Packet. See HostAdapterStatus,
768 TargetStatus, SenseDataLength, and SenseData in
769 that order for additional status information.
770 EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid.
771 The SCSI Request Packet was not sent, so no
772 additional status information is available.
773 EFI_UNSUPPORTED - The command described by the SCSI Request Packet
774 is not supported by the SCSI initiator(i.e., SCSI
775 Host Controller). The SCSI Request Packet was not
776 sent, so no additional status information is
778 EFI_TIMEOUT - A timeout occurred while waiting for the SCSI
779 Request Packet to execute. See HostAdapterStatus,
780 TargetStatus, SenseDataLength, and SenseData in
781 that order for additional status information.
784 SCSI_IO_DEV
*ScsiIoDevice
;
786 UINT8 Target
[TARGET_MAX_BYTES
];
787 EFI_EVENT PacketEvent
;
788 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ExtRequestPacket
;
789 SCSI_EVENT_DATA EventData
;
793 if (Packet
== NULL
) {
794 return EFI_INVALID_PARAMETER
;
797 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
798 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
800 if (ScsiIoDevice
->ExtScsiSupport
) {
801 ExtRequestPacket
= (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*) Packet
;
802 Status
= ScsiIoDevice
->ExtScsiPassThru
->PassThru (
803 ScsiIoDevice
->ExtScsiPassThru
,
811 Status
= gBS
->AllocatePool (
813 sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
),
814 (VOID
**)&WorkingBuffer
817 if (EFI_ERROR (Status
)) {
818 return EFI_DEVICE_ERROR
;
822 // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.
824 Status
= ScsiioToPassThruPacket(Packet
, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
);
825 if (EFI_ERROR(Status
)) {
826 gBS
->FreePool(WorkingBuffer
);
830 if ((ScsiIoDevice
->ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO
) && (Event
!= NULL
)) {
831 EventData
.Data1
= (VOID
*)Packet
;
832 EventData
.Data2
= Event
;
836 Status
= gBS
->CreateEvent (
843 if (EFI_ERROR(Status
)) {
844 gBS
->FreePool(WorkingBuffer
);
848 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
849 ScsiIoDevice
->ScsiPassThru
,
850 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
856 if (EFI_ERROR(Status
)) {
857 gBS
->FreePool(WorkingBuffer
);
858 gBS
->CloseEvent(PacketEvent
);
864 // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert
865 // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.
867 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
868 ScsiIoDevice
->ScsiPassThru
,
869 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
874 if (EFI_ERROR(Status
)) {
875 gBS
->FreePool(WorkingBuffer
);
879 PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
,Packet
);
881 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
882 // free WorkingBuffer.
884 gBS
->FreePool(WorkingBuffer
);
892 ScsiScanCreateDevice (
893 EFI_DRIVER_BINDING_PROTOCOL
*This
,
894 EFI_HANDLE Controller
,
895 SCSI_TARGET_ID
*TargetId
,
897 SCSI_BUS_DEVICE
*ScsiBusDev
903 Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.
907 This - Protocol instance pointer
908 Controller - Controller handle
909 Pun - The Pun of the SCSI device on the SCSI channel.
910 Lun - The Lun of the SCSI device on the SCSI channel.
911 ScsiBusDev - The pointer of SCSI_BUS_DEVICE
915 EFI_SUCCESS - Successfully to discover the device and attach ScsiIoProtocol to it.
916 EFI_OUT_OF_RESOURCES - Fail to discover the device.
921 SCSI_IO_DEV
*ScsiIoDevice
;
922 EFI_DEVICE_PATH_PROTOCOL
*ScsiDevicePath
;
924 Status
= gBS
->AllocatePool (
926 sizeof (SCSI_IO_DEV
),
927 (VOID
**) &ScsiIoDevice
929 if (EFI_ERROR (Status
)) {
933 ZeroMem (ScsiIoDevice
, sizeof (SCSI_IO_DEV
));
935 ScsiIoDevice
->Signature
= SCSI_IO_DEV_SIGNATURE
;
936 CopyMem(&ScsiIoDevice
->Pun
, TargetId
, TARGET_MAX_BYTES
);
937 ScsiIoDevice
->Lun
= Lun
;
939 if (ScsiBusDev
->ExtScsiSupport
) {
940 ScsiIoDevice
->ExtScsiPassThru
= ScsiBusDev
->ExtScsiInterface
;
941 ScsiIoDevice
->ExtScsiSupport
= TRUE
;
942 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ExtScsiPassThru
->Mode
->IoAlign
;
945 ScsiIoDevice
->ScsiPassThru
= ScsiBusDev
->ScsiInterface
;
946 ScsiIoDevice
->ExtScsiSupport
= FALSE
;
947 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ScsiPassThru
->Mode
->IoAlign
;
950 ScsiIoDevice
->ScsiIo
.GetDeviceType
= ScsiGetDeviceType
;
951 ScsiIoDevice
->ScsiIo
.GetDeviceLocation
= ScsiGetDeviceLocation
;
952 ScsiIoDevice
->ScsiIo
.ResetBus
= ScsiResetBus
;
953 ScsiIoDevice
->ScsiIo
.ResetDevice
= ScsiResetDevice
;
954 ScsiIoDevice
->ScsiIo
.ExecuteScsiCommand
= ScsiExecuteSCSICommand
;
957 if (!DiscoverScsiDevice (ScsiIoDevice
)) {
958 gBS
->FreePool (ScsiIoDevice
);
959 return EFI_OUT_OF_RESOURCES
;
965 if (ScsiIoDevice
->ExtScsiSupport
){
966 Status
= ScsiIoDevice
->ExtScsiPassThru
->BuildDevicePath (
967 ScsiIoDevice
->ExtScsiPassThru
,
968 &ScsiIoDevice
->Pun
.ScsiId
.ExtScsi
[0],
972 if (Status
== EFI_OUT_OF_RESOURCES
) {
973 gBS
->FreePool (ScsiIoDevice
);
977 Status
= ScsiIoDevice
->ScsiPassThru
->BuildDevicePath (
978 ScsiIoDevice
->ScsiPassThru
,
979 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
983 if (Status
== EFI_OUT_OF_RESOURCES
) {
984 gBS
->FreePool (ScsiIoDevice
);
989 ScsiIoDevice
->DevicePath
= AppendDevicePathNode (
990 ScsiBusDev
->DevicePath
,
994 // The memory space for ScsiDevicePath is allocated in
995 // ScsiPassThru->BuildDevicePath() function; It is no longer used
996 // after EfiAppendDevicePathNode,so free the memory it occupies.
998 gBS
->FreePool (ScsiDevicePath
);
1000 if (ScsiIoDevice
->DevicePath
== NULL
) {
1001 gBS
->FreePool (ScsiIoDevice
);
1002 return EFI_OUT_OF_RESOURCES
;
1005 Status
= gBS
->InstallMultipleProtocolInterfaces (
1006 &ScsiIoDevice
->Handle
,
1007 &gEfiDevicePathProtocolGuid
,
1008 ScsiIoDevice
->DevicePath
,
1009 &gEfiScsiIoProtocolGuid
,
1010 &ScsiIoDevice
->ScsiIo
,
1013 if (EFI_ERROR (Status
)) {
1014 gBS
->FreePool (ScsiIoDevice
);
1015 return EFI_OUT_OF_RESOURCES
;
1017 if (ScsiBusDev
->ExtScsiSupport
) {
1020 &gEfiExtScsiPassThruProtocolGuid
,
1021 (VOID
**) &(ScsiBusDev
->ExtScsiInterface
),
1022 This
->DriverBindingHandle
,
1023 ScsiIoDevice
->Handle
,
1024 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1029 &gEfiScsiPassThruProtocolGuid
,
1030 (VOID
**) &(ScsiBusDev
->ScsiInterface
),
1031 This
->DriverBindingHandle
,
1032 ScsiIoDevice
->Handle
,
1033 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1042 DiscoverScsiDevice (
1043 SCSI_IO_DEV
*ScsiIoDevice
1047 Routine Description:
1049 Discovery SCSI Device
1053 ScsiIoDevice - The pointer of SCSI_IO_DEV
1057 TRUE - Find SCSI Device and verify it.
1058 FALSE - Unable to find SCSI Device.
1063 UINT32 InquiryDataLength
;
1064 UINT8 SenseDataLength
;
1065 UINT8 HostAdapterStatus
;
1067 EFI_SCSI_SENSE_DATA SenseData
;
1068 EFI_SCSI_INQUIRY_DATA InquiryData
;
1070 HostAdapterStatus
= 0;
1073 // Using Inquiry command to scan for the device
1075 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1076 SenseDataLength
= sizeof (EFI_SCSI_SENSE_DATA
);
1078 Status
= ScsiInquiryCommand (
1079 &ScsiIoDevice
->ScsiIo
,
1080 EfiScsiStallSeconds (1),
1081 (VOID
*) &SenseData
,
1085 (VOID
*) &InquiryData
,
1089 if (EFI_ERROR (Status
)) {
1091 // ParseSenseData (&SenseData,SenseDataLength);
1096 // Retrieved inquiry data successfully
1098 if ((InquiryData
.Peripheral_Qualifier
!= 0) &&
1099 (InquiryData
.Peripheral_Qualifier
!= 3)) {
1103 if (InquiryData
.Peripheral_Qualifier
== 3) {
1104 if (InquiryData
.Peripheral_Type
!= 0x1f) {
1109 if (0x1e >= InquiryData
.Peripheral_Type
>= 0xa) {
1114 // valid device type and peripheral qualifier combination.
1116 ScsiIoDevice
->ScsiDeviceType
= InquiryData
.Peripheral_Type
;
1117 ScsiIoDevice
->RemovableDevice
= InquiryData
.RMB
;
1118 if (InquiryData
.Version
== 0) {
1119 ScsiIoDevice
->ScsiVersion
= 0;
1122 // ANSI-approved version
1124 ScsiIoDevice
->ScsiVersion
= (UINT8
) (InquiryData
.Version
& 0x03);
1134 ScsiioToPassThruPacket (
1135 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
1136 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
1140 Routine Description:
1142 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to
1143 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet
1147 Packet - The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1148 CommandPacket - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1157 //EFI 1.10 doesn't support Bi-Direction Command.
1159 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL
) {
1160 return EFI_UNSUPPORTED
;
1163 ZeroMem (CommandPacket
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1165 CommandPacket
->Timeout
= Packet
->Timeout
;
1166 CommandPacket
->Cdb
= Packet
->Cdb
;
1167 CommandPacket
->CdbLength
= Packet
->CdbLength
;
1168 CommandPacket
->DataDirection
= Packet
->DataDirection
;
1169 CommandPacket
->HostAdapterStatus
= Packet
->HostAdapterStatus
;
1170 CommandPacket
->TargetStatus
= Packet
->TargetStatus
;
1171 CommandPacket
->SenseData
= Packet
->SenseData
;
1172 CommandPacket
->SenseDataLength
= Packet
->SenseDataLength
;
1174 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1175 CommandPacket
->DataBuffer
= Packet
->InDataBuffer
;
1176 CommandPacket
->TransferLength
= Packet
->InTransferLength
;
1177 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1178 CommandPacket
->DataBuffer
= Packet
->OutDataBuffer
;
1179 CommandPacket
->TransferLength
= Packet
->OutTransferLength
;
1188 PassThruToScsiioPacket (
1189 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
1190 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
1194 Routine Description:
1196 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to
1197 EFI_SCSI_IO_SCSI_REQUEST_PACKET packet
1201 ScsiPacket - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1202 Packet - The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1210 Packet
->Timeout
= ScsiPacket
->Timeout
;
1211 Packet
->Cdb
= ScsiPacket
->Cdb
;
1212 Packet
->CdbLength
= ScsiPacket
->CdbLength
;
1213 Packet
->DataDirection
= ScsiPacket
->DataDirection
;
1214 Packet
->HostAdapterStatus
= ScsiPacket
->HostAdapterStatus
;
1215 Packet
->TargetStatus
= ScsiPacket
->TargetStatus
;
1216 Packet
->SenseData
= ScsiPacket
->SenseData
;
1217 Packet
->SenseDataLength
= ScsiPacket
->SenseDataLength
;
1219 if (ScsiPacket
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1220 Packet
->InDataBuffer
= ScsiPacket
->DataBuffer
;
1221 Packet
->InTransferLength
= ScsiPacket
->TransferLength
;
1222 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1223 Packet
->OutDataBuffer
= ScsiPacket
->DataBuffer
;
1224 Packet
->OutTransferLength
= ScsiPacket
->TransferLength
;
1241 Routine Description:
1243 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
1248 Event - The instance of EFI_EVENT.
1249 Context - The parameter passed in.
1257 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
;
1258 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
;
1259 EFI_EVENT CallerEvent
;
1260 SCSI_EVENT_DATA
*PassData
;
1262 PassData
= (SCSI_EVENT_DATA
*)Context
;
1263 Packet
= (EFI_SCSI_IO_SCSI_REQUEST_PACKET
*)PassData
->Data1
;
1264 ScsiPacket
= (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
;
1267 // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.
1269 PassThruToScsiioPacket(ScsiPacket
, Packet
);
1272 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1273 // free WorkingBuffer.
1275 gBS
->FreePool(WorkingBuffer
);
1278 // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.
1280 CallerEvent
= PassData
->Data2
;
1281 gBS
->CloseEvent(Event
);
1282 gBS
->SignalEvent(CallerEvent
);