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 DEBUG ((EFI_D_ERROR
, "ScsiExted Support: %d Frome First Target: %d\r\n" , ScsiBusDev
->ExtScsiSupport
, FromFirstTarget
));
397 while(ScanOtherPuns
) {
398 if (FromFirstTarget
) {
400 // Remaining Device Path is NULL, scan all the possible Puns in the
403 if (ScsiBusDev
->ExtScsiSupport
) {
404 Status
= ScsiBusDev
->ExtScsiInterface
->GetNextTargetLun (ScsiBusDev
->ExtScsiInterface
, &TargetId
, &Lun
);
406 Status
= ScsiBusDev
->ScsiInterface
->GetNextDevice (ScsiBusDev
->ScsiInterface
, &ScsiTargetId
->ScsiId
.Scsi
, &Lun
);
408 DEBUG ((EFI_D_ERROR
, "ScsiExte Error= %r\r\n" , Status
));
409 if (EFI_ERROR (Status
)) {
411 // no legal Pun and Lun found any more
416 ScanOtherPuns
= FALSE
;
419 // Avoid creating handle for the host adapter.
421 if (ScsiBusDev
->ExtScsiSupport
) {
422 if ((ScsiTargetId
->ScsiId
.Scsi
) == ScsiBusDev
->ExtScsiInterface
->Mode
->AdapterId
) {
426 if ((ScsiTargetId
->ScsiId
.Scsi
) == ScsiBusDev
->ScsiInterface
->Mode
->AdapterId
) {
431 // Scan for the scsi device, if it attaches to the scsi bus,
432 // then create handle and install scsi i/o protocol.
434 Status
= ScsiScanCreateDevice (This
, Controller
, ScsiTargetId
, Lun
, ScsiBusDev
);
435 DEBUG ((EFI_D_ERROR
, "CreateDevice %d, %d at %p Status = %r\r\n" , ScsiTargetId
, Lun
, Controller
, Status
));
437 gBS
->FreePool (ScsiTargetId
);
442 if (ScsiBusDev
!= NULL
) {
443 gBS
->FreePool (ScsiBusDev
);
446 if (ExtScsiSupport
) {
449 &gEfiExtScsiPassThruProtocolGuid
,
450 This
->DriverBindingHandle
,
453 if (!EFI_ERROR (PassThruStatus
)) {
456 &gEfiScsiPassThruProtocolGuid
,
457 This
->DriverBindingHandle
,
464 &gEfiScsiPassThruProtocolGuid
,
465 This
->DriverBindingHandle
,
474 SCSIBusDriverBindingStop (
475 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
476 IN EFI_HANDLE Controller
,
477 IN UINTN NumberOfChildren
,
478 IN EFI_HANDLE
*ChildHandleBuffer
484 Stop this driver on ControllerHandle. Support stoping any child handles
485 created by this driver.
489 This - Protocol instance pointer.
490 Controller - Handle of device to stop driver on
491 NumberOfChildren - Number of Children in the ChildHandleBuffer
492 ChildHandleBuffer - List of handles for the children we need to stop.
501 BOOLEAN AllChildrenStopped
;
503 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
504 SCSI_IO_DEV
*ScsiIoDevice
;
506 EFI_SCSI_BUS_PROTOCOL
*Scsidentifier
;
507 SCSI_BUS_DEVICE
*ScsiBusDev
;
509 if (NumberOfChildren
== 0) {
511 // Get the SCSI_BUS_DEVICE
513 Status
= gBS
->OpenProtocol (
515 &mScsiBusProtocolGuid
,
516 (VOID
**) &Scsidentifier
,
517 This
->DriverBindingHandle
,
519 EFI_OPEN_PROTOCOL_GET_PROTOCOL
522 if (EFI_ERROR (Status
)) {
523 return EFI_DEVICE_ERROR
;
526 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier
);
529 // Uninstall SCSI Bus Protocol
531 gBS
->UninstallProtocolInterface (
533 &mScsiBusProtocolGuid
,
534 &ScsiBusDev
->BusIdentify
538 // Close the bus driver
540 if (ScsiBusDev
->ExtScsiSupport
) {
543 &gEfiExtScsiPassThruProtocolGuid
,
544 This
->DriverBindingHandle
,
550 &gEfiScsiPassThruProtocolGuid
,
551 This
->DriverBindingHandle
,
558 &gEfiDevicePathProtocolGuid
,
559 This
->DriverBindingHandle
,
562 gBS
->FreePool (ScsiBusDev
);
566 AllChildrenStopped
= TRUE
;
568 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
570 Status
= gBS
->OpenProtocol (
571 ChildHandleBuffer
[Index
],
572 &gEfiScsiIoProtocolGuid
,
574 This
->DriverBindingHandle
,
576 EFI_OPEN_PROTOCOL_GET_PROTOCOL
578 if (EFI_ERROR (Status
)) {
579 AllChildrenStopped
= FALSE
;
583 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (ScsiIo
);
585 // Close the child handle
587 if (ScsiIoDevice
->ExtScsiSupport
) {
588 Status
= gBS
->CloseProtocol (
590 &gEfiExtScsiPassThruProtocolGuid
,
591 This
->DriverBindingHandle
,
592 ChildHandleBuffer
[Index
]
596 Status
= gBS
->CloseProtocol (
598 &gEfiScsiPassThruProtocolGuid
,
599 This
->DriverBindingHandle
,
600 ChildHandleBuffer
[Index
]
604 Status
= gBS
->UninstallMultipleProtocolInterfaces (
605 ChildHandleBuffer
[Index
],
606 &gEfiDevicePathProtocolGuid
,
607 ScsiIoDevice
->DevicePath
,
608 &gEfiScsiIoProtocolGuid
,
609 &ScsiIoDevice
->ScsiIo
,
612 if (EFI_ERROR (Status
)) {
613 AllChildrenStopped
= FALSE
;
614 if (ScsiIoDevice
->ExtScsiSupport
) {
617 &gEfiExtScsiPassThruProtocolGuid
,
619 This
->DriverBindingHandle
,
620 ChildHandleBuffer
[Index
],
621 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
626 &gEfiScsiPassThruProtocolGuid
,
628 This
->DriverBindingHandle
,
629 ChildHandleBuffer
[Index
],
630 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
634 gBS
->FreePool (ScsiIoDevice
);
638 if (!AllChildrenStopped
) {
639 return EFI_DEVICE_ERROR
;
648 IN EFI_SCSI_IO_PROTOCOL
*This
,
649 OUT UINT8
*DeviceType
655 Retrieves the device type information of the SCSI Controller.
659 This - Protocol instance pointer.
660 DeviceType - A pointer to the device type information
661 retrieved from the SCSI Controller.
665 EFI_SUCCESS - Retrieves the device type information successfully.
666 EFI_INVALID_PARAMETER - The DeviceType is NULL.
670 SCSI_IO_DEV
*ScsiIoDevice
;
672 if (DeviceType
== NULL
) {
673 return EFI_INVALID_PARAMETER
;
676 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
677 *DeviceType
= ScsiIoDevice
->ScsiDeviceType
;
683 ScsiGetDeviceLocation (
684 IN EFI_SCSI_IO_PROTOCOL
*This
,
685 IN OUT UINT8
**Target
,
692 Retrieves the device location in the SCSI channel.
696 This - Protocol instance pointer.
697 Target - A pointer to the Target Array which represents ID of a SCSI device
699 Lun - A pointer to the LUN of the SCSI device on
704 EFI_SUCCESS - Retrieves the device location successfully.
705 EFI_INVALID_PARAMETER - The Target or Lun is NULL.
709 SCSI_IO_DEV
*ScsiIoDevice
;
711 if (Target
== NULL
|| Lun
== NULL
) {
712 return EFI_INVALID_PARAMETER
;
715 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
717 CopyMem (*Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
719 *Lun
= ScsiIoDevice
->Lun
;
727 IN EFI_SCSI_IO_PROTOCOL
*This
733 Resets the SCSI Bus that the SCSI Controller is attached to.
737 This - Protocol instance pointer.
741 EFI_SUCCESS - The SCSI bus is reset successfully.
742 EFI_DEVICE_ERROR - Errors encountered when resetting the SCSI bus.
743 EFI_UNSUPPORTED - The bus reset operation is not supported by the
744 SCSI Host Controller.
745 EFI_TIMEOUT - A timeout occurred while attempting to reset
749 SCSI_IO_DEV
*ScsiIoDevice
;
751 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
753 if (ScsiIoDevice
->ExtScsiSupport
){
754 return ScsiIoDevice
->ExtScsiPassThru
->ResetChannel (ScsiIoDevice
->ExtScsiPassThru
);
756 return ScsiIoDevice
->ScsiPassThru
->ResetChannel (ScsiIoDevice
->ScsiPassThru
);
763 IN EFI_SCSI_IO_PROTOCOL
*This
769 Resets the SCSI Controller that the device handle specifies.
773 This - Protocol instance pointer.
777 EFI_SUCCESS - Reset the SCSI controller successfully.
778 EFI_DEVICE_ERROR - Errors are encountered when resetting the
780 EFI_UNSUPPORTED - The SCSI bus does not support a device
782 EFI_TIMEOUT - A timeout occurred while attempting to
783 reset the SCSI Controller.
786 SCSI_IO_DEV
*ScsiIoDevice
;
787 UINT8 Target
[TARGET_MAX_BYTES
];
789 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
790 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
793 if (ScsiIoDevice
->ExtScsiSupport
) {
794 return ScsiIoDevice
->ExtScsiPassThru
->ResetTargetLun (
795 ScsiIoDevice
->ExtScsiPassThru
,
800 return ScsiIoDevice
->ScsiPassThru
->ResetTarget (
801 ScsiIoDevice
->ScsiPassThru
,
802 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
810 ScsiExecuteSCSICommand (
811 IN EFI_SCSI_IO_PROTOCOL
*This
,
812 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
813 IN EFI_EVENT Event OPTIONAL
819 Sends a SCSI Request Packet to the SCSI Controller for execution.
823 This - Protocol instance pointer.
824 Packet - The SCSI request packet to send to the SCSI
825 Controller specified by the device handle.
826 Event - If the SCSI bus where the SCSI device is attached
827 does not support non-blocking I/O, then Event is
828 ignored, and blocking I/O is performed.
829 If Event is NULL, then blocking I/O is performed.
830 If Event is not NULL and non-blocking I/O is
831 supported, then non-blocking I/O is performed,
832 and Event will be signaled when the SCSI Request
836 EFI_SUCCESS - The SCSI Request Packet was sent by the host
837 successfully, and TransferLength bytes were
838 transferred to/from DataBuffer.See
839 HostAdapterStatus, TargetStatus,
840 SenseDataLength, and SenseData in that order
841 for additional status information.
842 EFI_BAD_BUFFER_SIZE - The SCSI Request Packet was executed,
843 but the entire DataBuffer could not be transferred.
844 The actual number of bytes transferred is returned
845 in TransferLength. See HostAdapterStatus,
846 TargetStatus, SenseDataLength, and SenseData in
847 that order for additional status information.
848 EFI_NOT_READY - The SCSI Request Packet could not be sent because
849 there are too many SCSI Command Packets already
850 queued.The caller may retry again later.
851 EFI_DEVICE_ERROR - A device error occurred while attempting to send
852 the SCSI Request Packet. See HostAdapterStatus,
853 TargetStatus, SenseDataLength, and SenseData in
854 that order for additional status information.
855 EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid.
856 The SCSI Request Packet was not sent, so no
857 additional status information is available.
858 EFI_UNSUPPORTED - The command described by the SCSI Request Packet
859 is not supported by the SCSI initiator(i.e., SCSI
860 Host Controller). The SCSI Request Packet was not
861 sent, so no additional status information is
863 EFI_TIMEOUT - A timeout occurred while waiting for the SCSI
864 Request Packet to execute. See HostAdapterStatus,
865 TargetStatus, SenseDataLength, and SenseData in
866 that order for additional status information.
869 SCSI_IO_DEV
*ScsiIoDevice
;
871 UINT8 Target
[TARGET_MAX_BYTES
];
872 EFI_EVENT PacketEvent
;
873 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ExtRequestPacket
;
874 SCSI_EVENT_DATA EventData
;
878 if (Packet
== NULL
) {
879 return EFI_INVALID_PARAMETER
;
882 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
883 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
885 if (ScsiIoDevice
->ExtScsiSupport
) {
886 ExtRequestPacket
= (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*) Packet
;
887 Status
= ScsiIoDevice
->ExtScsiPassThru
->PassThru (
888 ScsiIoDevice
->ExtScsiPassThru
,
896 Status
= gBS
->AllocatePool (
898 sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
),
899 (VOID
**)&WorkingBuffer
902 if (EFI_ERROR (Status
)) {
903 return EFI_DEVICE_ERROR
;
907 // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.
909 Status
= ScsiioToPassThruPacket(Packet
, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
);
910 if (EFI_ERROR(Status
)) {
911 gBS
->FreePool(WorkingBuffer
);
915 if ((ScsiIoDevice
->ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO
) && (Event
!= NULL
)) {
916 EventData
.Data1
= (VOID
*)Packet
;
917 EventData
.Data2
= Event
;
921 Status
= gBS
->CreateEvent (
928 if (EFI_ERROR(Status
)) {
929 gBS
->FreePool(WorkingBuffer
);
933 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
934 ScsiIoDevice
->ScsiPassThru
,
935 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
941 if (EFI_ERROR(Status
)) {
942 gBS
->FreePool(WorkingBuffer
);
943 gBS
->CloseEvent(PacketEvent
);
949 // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert
950 // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.
952 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
953 ScsiIoDevice
->ScsiPassThru
,
954 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
959 if (EFI_ERROR(Status
)) {
960 gBS
->FreePool(WorkingBuffer
);
964 PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
,Packet
);
966 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
967 // free WorkingBuffer.
969 gBS
->FreePool(WorkingBuffer
);
977 ScsiScanCreateDevice (
978 EFI_DRIVER_BINDING_PROTOCOL
*This
,
979 EFI_HANDLE Controller
,
980 SCSI_TARGET_ID
*TargetId
,
982 SCSI_BUS_DEVICE
*ScsiBusDev
988 Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.
992 This - Protocol instance pointer
993 Controller - Controller handle
994 Pun - The Pun of the SCSI device on the SCSI channel.
995 Lun - The Lun of the SCSI device on the SCSI channel.
996 ScsiBusDev - The pointer of SCSI_BUS_DEVICE
1000 EFI_SUCCESS - Successfully to discover the device and attach ScsiIoProtocol to it.
1001 EFI_OUT_OF_RESOURCES - Fail to discover the device.
1006 SCSI_IO_DEV
*ScsiIoDevice
;
1007 EFI_DEVICE_PATH_PROTOCOL
*ScsiDevicePath
;
1009 Status
= gBS
->AllocatePool (
1010 EfiBootServicesData
,
1011 sizeof (SCSI_IO_DEV
),
1012 (VOID
**) &ScsiIoDevice
1014 if (EFI_ERROR (Status
)) {
1018 ZeroMem (ScsiIoDevice
, sizeof (SCSI_IO_DEV
));
1020 ScsiIoDevice
->Signature
= SCSI_IO_DEV_SIGNATURE
;
1021 CopyMem(&ScsiIoDevice
->Pun
, TargetId
, TARGET_MAX_BYTES
);
1022 ScsiIoDevice
->Lun
= Lun
;
1024 if (ScsiBusDev
->ExtScsiSupport
) {
1025 ScsiIoDevice
->ExtScsiPassThru
= ScsiBusDev
->ExtScsiInterface
;
1026 ScsiIoDevice
->ExtScsiSupport
= TRUE
;
1027 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ExtScsiPassThru
->Mode
->IoAlign
;
1030 ScsiIoDevice
->ScsiPassThru
= ScsiBusDev
->ScsiInterface
;
1031 ScsiIoDevice
->ExtScsiSupport
= FALSE
;
1032 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ScsiPassThru
->Mode
->IoAlign
;
1035 ScsiIoDevice
->ScsiIo
.GetDeviceType
= ScsiGetDeviceType
;
1036 ScsiIoDevice
->ScsiIo
.GetDeviceLocation
= ScsiGetDeviceLocation
;
1037 ScsiIoDevice
->ScsiIo
.ResetBus
= ScsiResetBus
;
1038 ScsiIoDevice
->ScsiIo
.ResetDevice
= ScsiResetDevice
;
1039 ScsiIoDevice
->ScsiIo
.ExecuteScsiCommand
= ScsiExecuteSCSICommand
;
1042 if (!DiscoverScsiDevice (ScsiIoDevice
)) {
1043 gBS
->FreePool (ScsiIoDevice
);
1044 return EFI_OUT_OF_RESOURCES
;
1050 if (ScsiIoDevice
->ExtScsiSupport
){
1051 Status
= ScsiIoDevice
->ExtScsiPassThru
->BuildDevicePath (
1052 ScsiIoDevice
->ExtScsiPassThru
,
1053 &ScsiIoDevice
->Pun
.ScsiId
.ExtScsi
[0],
1057 if (Status
== EFI_OUT_OF_RESOURCES
) {
1058 gBS
->FreePool (ScsiIoDevice
);
1062 Status
= ScsiIoDevice
->ScsiPassThru
->BuildDevicePath (
1063 ScsiIoDevice
->ScsiPassThru
,
1064 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
1068 if (Status
== EFI_OUT_OF_RESOURCES
) {
1069 gBS
->FreePool (ScsiIoDevice
);
1074 ScsiIoDevice
->DevicePath
= AppendDevicePathNode (
1075 ScsiBusDev
->DevicePath
,
1079 // The memory space for ScsiDevicePath is allocated in
1080 // ScsiPassThru->BuildDevicePath() function; It is no longer used
1081 // after EfiAppendDevicePathNode,so free the memory it occupies.
1083 gBS
->FreePool (ScsiDevicePath
);
1085 if (ScsiIoDevice
->DevicePath
== NULL
) {
1086 gBS
->FreePool (ScsiIoDevice
);
1087 return EFI_OUT_OF_RESOURCES
;
1090 Status
= gBS
->InstallMultipleProtocolInterfaces (
1091 &ScsiIoDevice
->Handle
,
1092 &gEfiDevicePathProtocolGuid
,
1093 ScsiIoDevice
->DevicePath
,
1094 &gEfiScsiIoProtocolGuid
,
1095 &ScsiIoDevice
->ScsiIo
,
1098 if (EFI_ERROR (Status
)) {
1099 gBS
->FreePool (ScsiIoDevice
);
1100 return EFI_OUT_OF_RESOURCES
;
1102 if (ScsiBusDev
->ExtScsiSupport
) {
1105 &gEfiExtScsiPassThruProtocolGuid
,
1106 (VOID
**) &(ScsiBusDev
->ExtScsiInterface
),
1107 This
->DriverBindingHandle
,
1108 ScsiIoDevice
->Handle
,
1109 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1114 &gEfiScsiPassThruProtocolGuid
,
1115 (VOID
**) &(ScsiBusDev
->ScsiInterface
),
1116 This
->DriverBindingHandle
,
1117 ScsiIoDevice
->Handle
,
1118 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1127 DiscoverScsiDevice (
1128 SCSI_IO_DEV
*ScsiIoDevice
1132 Routine Description:
1134 Discovery SCSI Device
1138 ScsiIoDevice - The pointer of SCSI_IO_DEV
1142 TRUE - Find SCSI Device and verify it.
1143 FALSE - Unable to find SCSI Device.
1148 UINT32 InquiryDataLength
;
1149 UINT8 SenseDataLength
;
1150 UINT8 HostAdapterStatus
;
1152 EFI_SCSI_SENSE_DATA SenseData
;
1153 EFI_SCSI_INQUIRY_DATA InquiryData
;
1155 HostAdapterStatus
= 0;
1158 // Using Inquiry command to scan for the device
1160 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1161 SenseDataLength
= sizeof (EFI_SCSI_SENSE_DATA
);
1163 Status
= ScsiInquiryCommand (
1164 &ScsiIoDevice
->ScsiIo
,
1165 EfiScsiStallSeconds (1),
1166 (VOID
*) &SenseData
,
1170 (VOID
*) &InquiryData
,
1174 if (EFI_ERROR (Status
)) {
1176 // ParseSenseData (&SenseData,SenseDataLength);
1181 // Retrieved inquiry data successfully
1183 if ((InquiryData
.Peripheral_Qualifier
!= 0) &&
1184 (InquiryData
.Peripheral_Qualifier
!= 3)) {
1188 if (InquiryData
.Peripheral_Qualifier
== 3) {
1189 if (InquiryData
.Peripheral_Type
!= 0x1f) {
1194 if (0x1e >= InquiryData
.Peripheral_Type
&& InquiryData
.Peripheral_Type
>= 0xa) {
1199 // valid device type and peripheral qualifier combination.
1201 ScsiIoDevice
->ScsiDeviceType
= InquiryData
.Peripheral_Type
;
1202 ScsiIoDevice
->RemovableDevice
= InquiryData
.RMB
;
1203 if (InquiryData
.Version
== 0) {
1204 ScsiIoDevice
->ScsiVersion
= 0;
1207 // ANSI-approved version
1209 ScsiIoDevice
->ScsiVersion
= (UINT8
) (InquiryData
.Version
& 0x03);
1219 ScsiioToPassThruPacket (
1220 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
1221 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
1225 Routine Description:
1227 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to
1228 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet
1232 Packet - The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1233 CommandPacket - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1242 //EFI 1.10 doesn't support Bi-Direction Command.
1244 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL
) {
1245 return EFI_UNSUPPORTED
;
1248 ZeroMem (CommandPacket
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1250 CommandPacket
->Timeout
= Packet
->Timeout
;
1251 CommandPacket
->Cdb
= Packet
->Cdb
;
1252 CommandPacket
->CdbLength
= Packet
->CdbLength
;
1253 CommandPacket
->DataDirection
= Packet
->DataDirection
;
1254 CommandPacket
->HostAdapterStatus
= Packet
->HostAdapterStatus
;
1255 CommandPacket
->TargetStatus
= Packet
->TargetStatus
;
1256 CommandPacket
->SenseData
= Packet
->SenseData
;
1257 CommandPacket
->SenseDataLength
= Packet
->SenseDataLength
;
1259 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1260 CommandPacket
->DataBuffer
= Packet
->InDataBuffer
;
1261 CommandPacket
->TransferLength
= Packet
->InTransferLength
;
1262 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1263 CommandPacket
->DataBuffer
= Packet
->OutDataBuffer
;
1264 CommandPacket
->TransferLength
= Packet
->OutTransferLength
;
1273 PassThruToScsiioPacket (
1274 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
1275 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
1279 Routine Description:
1281 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to
1282 EFI_SCSI_IO_SCSI_REQUEST_PACKET packet
1286 ScsiPacket - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1287 Packet - The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1295 Packet
->Timeout
= ScsiPacket
->Timeout
;
1296 Packet
->Cdb
= ScsiPacket
->Cdb
;
1297 Packet
->CdbLength
= ScsiPacket
->CdbLength
;
1298 Packet
->DataDirection
= ScsiPacket
->DataDirection
;
1299 Packet
->HostAdapterStatus
= ScsiPacket
->HostAdapterStatus
;
1300 Packet
->TargetStatus
= ScsiPacket
->TargetStatus
;
1301 Packet
->SenseData
= ScsiPacket
->SenseData
;
1302 Packet
->SenseDataLength
= ScsiPacket
->SenseDataLength
;
1304 if (ScsiPacket
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1305 Packet
->InDataBuffer
= ScsiPacket
->DataBuffer
;
1306 Packet
->InTransferLength
= ScsiPacket
->TransferLength
;
1307 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1308 Packet
->OutDataBuffer
= ScsiPacket
->DataBuffer
;
1309 Packet
->OutTransferLength
= ScsiPacket
->TransferLength
;
1326 Routine Description:
1328 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
1333 Event - The instance of EFI_EVENT.
1334 Context - The parameter passed in.
1342 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
;
1343 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
;
1344 EFI_EVENT CallerEvent
;
1345 SCSI_EVENT_DATA
*PassData
;
1347 PassData
= (SCSI_EVENT_DATA
*)Context
;
1348 Packet
= (EFI_SCSI_IO_SCSI_REQUEST_PACKET
*)PassData
->Data1
;
1349 ScsiPacket
= (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
;
1352 // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.
1354 PassThruToScsiioPacket(ScsiPacket
, Packet
);
1357 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1358 // free WorkingBuffer.
1360 gBS
->FreePool(WorkingBuffer
);
1363 // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.
1365 CallerEvent
= PassData
->Data2
;
1366 gBS
->CloseEvent(Event
);
1367 gBS
->SignalEvent(CallerEvent
);