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 EFI_GUID mScsiBusProtocolGuid
= EFI_SCSI_BUS_PROTOCOL_GUID
;
59 ScsiioToPassThruPacket (
60 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
61 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
67 PassThruToScsiioPacket (
68 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
69 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
79 The user Entry Point for module ScsiBus. The user code starts with this function.
81 @param[in] ImageHandle The firmware allocated handle for the EFI image.
82 @param[in] SystemTable A pointer to the EFI System Table.
84 @retval EFI_SUCCESS The entry point is executed successfully.
85 @retval other Some error occurs when executing this entry point.
91 IN EFI_HANDLE ImageHandle
,
92 IN EFI_SYSTEM_TABLE
*SystemTable
98 // Install driver model protocol(s).
100 Status
= EfiLibInstallDriverBindingComponentName2 (
103 &gSCSIBusDriverBinding
,
105 &gScsiBusComponentName
,
106 &gScsiBusComponentName2
108 ASSERT_EFI_ERROR (Status
);
115 SCSIBusDriverBindingSupported (
116 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
117 IN EFI_HANDLE Controller
,
118 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
124 Test to see if this driver supports ControllerHandle. Any ControllerHandle
125 that has ExtScsiPassThruProtocol/ScsiPassThruProtocol installed will be supported.
129 This - Protocol instance pointer.
130 Controller - Handle of device to test
131 RemainingDevicePath - Not used
135 EFI_SUCCESS - This driver supports this device.
136 EFI_UNSUPPORTED - This driver does not support this device.
142 EFI_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
143 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtPassThru
;
145 // Check for the existence of Extended SCSI Pass Thru Protocol and SCSI Pass Thru Protocol
147 Status
= gBS
->OpenProtocol (
149 &gEfiExtScsiPassThruProtocolGuid
,
150 (VOID
**)&ExtPassThru
,
151 This
->DriverBindingHandle
,
153 EFI_OPEN_PROTOCOL_BY_DRIVER
156 if (Status
== EFI_ALREADY_STARTED
) {
160 if (EFI_ERROR (Status
)) {
161 Status
= gBS
->OpenProtocol (
163 &gEfiScsiPassThruProtocolGuid
,
165 This
->DriverBindingHandle
,
167 EFI_OPEN_PROTOCOL_BY_DRIVER
170 if (Status
== EFI_ALREADY_STARTED
) {
174 if (EFI_ERROR (Status
)) {
180 &gEfiScsiPassThruProtocolGuid
,
181 This
->DriverBindingHandle
,
189 &gEfiExtScsiPassThruProtocolGuid
,
190 This
->DriverBindingHandle
,
199 SCSIBusDriverBindingStart (
200 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
201 IN EFI_HANDLE Controller
,
202 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
207 Starting the SCSI Bus Driver
210 This - Protocol instance pointer.
211 Controller - Handle of device to test
212 RemainingDevicePath - Not used
215 EFI_SUCCESS - This driver supports this device.
216 EFI_UNSUPPORTED - This driver does not support this device.
217 EFI_DEVICE_ERROR - This driver cannot be started due to device Error
223 BOOLEAN ScanOtherPuns
;
224 BOOLEAN FromFirstTarget
;
225 BOOLEAN ExtScsiSupport
;
227 EFI_STATUS DevicePathStatus
;
228 EFI_STATUS PassThruStatus
;
229 SCSI_BUS_DEVICE
*ScsiBusDev
;
230 SCSI_TARGET_ID
*ScsiTargetId
;
231 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
232 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiInterface
;
233 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiInterface
;
234 EFI_SCSI_BUS_PROTOCOL
*BusIdentify
;
238 ScanOtherPuns
= TRUE
;
239 FromFirstTarget
= FALSE
;
240 ExtScsiSupport
= FALSE
;
241 PassThruStatus
= EFI_SUCCESS
;
243 ScsiTargetId
= AllocateZeroPool(sizeof(SCSI_TARGET_ID
));
244 if (ScsiTargetId
== NULL
) {
245 return EFI_OUT_OF_RESOURCES
;
248 TargetId
= &ScsiTargetId
->ScsiId
.ExtScsi
[0];
250 DevicePathStatus
= gBS
->OpenProtocol (
252 &gEfiDevicePathProtocolGuid
,
253 (VOID
**) &ParentDevicePath
,
254 This
->DriverBindingHandle
,
256 EFI_OPEN_PROTOCOL_BY_DRIVER
258 if (EFI_ERROR (DevicePathStatus
) && (DevicePathStatus
!= EFI_ALREADY_STARTED
)) {
259 return DevicePathStatus
;
263 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
264 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
265 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
267 Status
= gBS
->OpenProtocol (
269 &gEfiExtScsiPassThruProtocolGuid
,
270 (VOID
**) &ExtScsiInterface
,
271 This
->DriverBindingHandle
,
273 EFI_OPEN_PROTOCOL_BY_DRIVER
276 // Fail to open UEFI ExtendPassThru Protocol, then try to open EFI PassThru Protocol instead.
278 if (EFI_ERROR(Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
279 Status
= gBS
->OpenProtocol (
281 &gEfiScsiPassThruProtocolGuid
,
282 (VOID
**) &ScsiInterface
,
283 This
->DriverBindingHandle
,
285 EFI_OPEN_PROTOCOL_BY_DRIVER
288 // Fail to open EFI PassThru Protocol, Close the DevicePathProtocol if it is opened by this time.
290 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
291 if (!EFI_ERROR(DevicePathStatus
)) {
294 &gEfiDevicePathProtocolGuid
,
295 This
->DriverBindingHandle
,
303 // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol
304 // with BY_DRIVER if it is also present on the handle. The intent is to prevent
305 // another SCSI Bus Driver to work on the same host handle.
307 ExtScsiSupport
= TRUE
;
308 PassThruStatus
= gBS
->OpenProtocol (
310 &gEfiScsiPassThruProtocolGuid
,
311 (VOID
**) &ScsiInterface
,
312 This
->DriverBindingHandle
,
314 EFI_OPEN_PROTOCOL_BY_DRIVER
318 if (Status
!= EFI_ALREADY_STARTED
) {
320 // Go through here means either ExtPassThru or PassThru Protocol is successfully opened
321 // on this handle for this time. Then construct Host controller private data.
324 ScsiBusDev
= AllocateZeroPool(sizeof(SCSI_BUS_DEVICE
));
325 if (ScsiBusDev
== NULL
) {
326 Status
= EFI_OUT_OF_RESOURCES
;
329 ScsiBusDev
->Signature
= SCSI_BUS_DEVICE_SIGNATURE
;
330 ScsiBusDev
->ExtScsiSupport
= ExtScsiSupport
;
331 ScsiBusDev
->DevicePath
= ParentDevicePath
;
332 if (ScsiBusDev
->ExtScsiSupport
) {
333 ScsiBusDev
->ExtScsiInterface
= ExtScsiInterface
;
335 ScsiBusDev
->ScsiInterface
= ScsiInterface
;
339 // Install EFI_SCSI_BUS_PROTOCOL to the controller handle, So ScsiBusDev could be
340 // retrieved on this controller handle. With ScsiBusDev, we can know which PassThru
341 // Protocol is present on the handle, UEFI ExtPassThru Protocol or EFI PassThru Protocol.
343 Status
= gBS
->InstallProtocolInterface (
345 &mScsiBusProtocolGuid
,
346 EFI_NATIVE_INTERFACE
,
347 &ScsiBusDev
->BusIdentify
349 if (EFI_ERROR (Status
)) {
354 // Go through here means Start() is re-invoked again, nothing special is required to do except
355 // picking up Host controller private information.
357 Status
= gBS
->OpenProtocol (
359 &mScsiBusProtocolGuid
,
360 (VOID
**) &BusIdentify
,
361 This
->DriverBindingHandle
,
363 EFI_OPEN_PROTOCOL_GET_PROTOCOL
366 if (EFI_ERROR (Status
)) {
369 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify
);
372 if (RemainingDevicePath
== NULL
) {
373 SetMem (ScsiTargetId
, TARGET_MAX_BYTES
,0xFF);
375 FromFirstTarget
= TRUE
;
377 if (ScsiBusDev
->ExtScsiSupport
) {
378 ScsiBusDev
->ExtScsiInterface
->GetTargetLun (ScsiBusDev
->ExtScsiInterface
, RemainingDevicePath
, &TargetId
, &Lun
);
380 ScsiBusDev
->ScsiInterface
->GetTargetLun (ScsiBusDev
->ScsiInterface
, RemainingDevicePath
, &ScsiTargetId
->ScsiId
.Scsi
, &Lun
);
384 while(ScanOtherPuns
) {
385 if (FromFirstTarget
) {
387 // Remaining Device Path is NULL, scan all the possible Puns in the
390 if (ScsiBusDev
->ExtScsiSupport
) {
391 Status
= ScsiBusDev
->ExtScsiInterface
->GetNextTargetLun (ScsiBusDev
->ExtScsiInterface
, &TargetId
, &Lun
);
393 Status
= ScsiBusDev
->ScsiInterface
->GetNextDevice (ScsiBusDev
->ScsiInterface
, &ScsiTargetId
->ScsiId
.Scsi
, &Lun
);
395 if (EFI_ERROR (Status
)) {
397 // no legal Pun and Lun found any more
402 ScanOtherPuns
= FALSE
;
405 // Avoid creating handle for the host adapter.
407 if (ScsiBusDev
->ExtScsiSupport
) {
408 if ((ScsiTargetId
->ScsiId
.Scsi
) == ScsiBusDev
->ExtScsiInterface
->Mode
->AdapterId
) {
412 if ((ScsiTargetId
->ScsiId
.Scsi
) == ScsiBusDev
->ScsiInterface
->Mode
->AdapterId
) {
417 // Scan for the scsi device, if it attaches to the scsi bus,
418 // then create handle and install scsi i/o protocol.
420 Status
= ScsiScanCreateDevice (This
, Controller
, ScsiTargetId
, Lun
, ScsiBusDev
);
422 gBS
->FreePool (ScsiTargetId
);
427 if (ScsiBusDev
!= NULL
) {
428 gBS
->FreePool (ScsiBusDev
);
431 if (ExtScsiSupport
) {
434 &gEfiExtScsiPassThruProtocolGuid
,
435 This
->DriverBindingHandle
,
438 if (!EFI_ERROR (PassThruStatus
)) {
441 &gEfiScsiPassThruProtocolGuid
,
442 This
->DriverBindingHandle
,
449 &gEfiScsiPassThruProtocolGuid
,
450 This
->DriverBindingHandle
,
459 SCSIBusDriverBindingStop (
460 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
461 IN EFI_HANDLE Controller
,
462 IN UINTN NumberOfChildren
,
463 IN EFI_HANDLE
*ChildHandleBuffer
469 Stop this driver on ControllerHandle. Support stoping any child handles
470 created by this driver.
474 This - Protocol instance pointer.
475 Controller - Handle of device to stop driver on
476 NumberOfChildren - Number of Children in the ChildHandleBuffer
477 ChildHandleBuffer - List of handles for the children we need to stop.
486 BOOLEAN AllChildrenStopped
;
488 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
489 SCSI_IO_DEV
*ScsiIoDevice
;
491 EFI_SCSI_BUS_PROTOCOL
*Scsidentifier
;
492 SCSI_BUS_DEVICE
*ScsiBusDev
;
494 if (NumberOfChildren
== 0) {
496 // Get the SCSI_BUS_DEVICE
498 Status
= gBS
->OpenProtocol (
500 &mScsiBusProtocolGuid
,
501 (VOID
**) &Scsidentifier
,
502 This
->DriverBindingHandle
,
504 EFI_OPEN_PROTOCOL_GET_PROTOCOL
507 if (EFI_ERROR (Status
)) {
508 return EFI_DEVICE_ERROR
;
511 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier
);
514 // Uninstall SCSI Bus Protocol
516 gBS
->UninstallProtocolInterface (
518 &mScsiBusProtocolGuid
,
519 &ScsiBusDev
->BusIdentify
523 // Close the bus driver
525 if (ScsiBusDev
->ExtScsiSupport
) {
528 &gEfiExtScsiPassThruProtocolGuid
,
529 This
->DriverBindingHandle
,
535 &gEfiScsiPassThruProtocolGuid
,
536 This
->DriverBindingHandle
,
543 &gEfiDevicePathProtocolGuid
,
544 This
->DriverBindingHandle
,
547 gBS
->FreePool (ScsiBusDev
);
551 AllChildrenStopped
= TRUE
;
553 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
555 Status
= gBS
->OpenProtocol (
556 ChildHandleBuffer
[Index
],
557 &gEfiScsiIoProtocolGuid
,
559 This
->DriverBindingHandle
,
561 EFI_OPEN_PROTOCOL_GET_PROTOCOL
563 if (EFI_ERROR (Status
)) {
564 AllChildrenStopped
= FALSE
;
568 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (ScsiIo
);
570 // Close the child handle
572 if (ScsiIoDevice
->ExtScsiSupport
) {
573 Status
= gBS
->CloseProtocol (
575 &gEfiExtScsiPassThruProtocolGuid
,
576 This
->DriverBindingHandle
,
577 ChildHandleBuffer
[Index
]
581 Status
= gBS
->CloseProtocol (
583 &gEfiScsiPassThruProtocolGuid
,
584 This
->DriverBindingHandle
,
585 ChildHandleBuffer
[Index
]
589 Status
= gBS
->UninstallMultipleProtocolInterfaces (
590 ChildHandleBuffer
[Index
],
591 &gEfiDevicePathProtocolGuid
,
592 ScsiIoDevice
->DevicePath
,
593 &gEfiScsiIoProtocolGuid
,
594 &ScsiIoDevice
->ScsiIo
,
597 if (EFI_ERROR (Status
)) {
598 AllChildrenStopped
= FALSE
;
599 if (ScsiIoDevice
->ExtScsiSupport
) {
602 &gEfiExtScsiPassThruProtocolGuid
,
604 This
->DriverBindingHandle
,
605 ChildHandleBuffer
[Index
],
606 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
611 &gEfiScsiPassThruProtocolGuid
,
613 This
->DriverBindingHandle
,
614 ChildHandleBuffer
[Index
],
615 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
619 gBS
->FreePool (ScsiIoDevice
);
623 if (!AllChildrenStopped
) {
624 return EFI_DEVICE_ERROR
;
633 IN EFI_SCSI_IO_PROTOCOL
*This
,
634 OUT UINT8
*DeviceType
640 Retrieves the device type information of the SCSI Controller.
644 This - Protocol instance pointer.
645 DeviceType - A pointer to the device type information
646 retrieved from the SCSI Controller.
650 EFI_SUCCESS - Retrieves the device type information successfully.
651 EFI_INVALID_PARAMETER - The DeviceType is NULL.
655 SCSI_IO_DEV
*ScsiIoDevice
;
657 if (DeviceType
== NULL
) {
658 return EFI_INVALID_PARAMETER
;
661 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
662 *DeviceType
= ScsiIoDevice
->ScsiDeviceType
;
668 ScsiGetDeviceLocation (
669 IN EFI_SCSI_IO_PROTOCOL
*This
,
670 IN OUT UINT8
**Target
,
677 Retrieves the device location in the SCSI channel.
681 This - Protocol instance pointer.
682 Target - A pointer to the Target Array which represents ID of a SCSI device
684 Lun - A pointer to the LUN of the SCSI device on
689 EFI_SUCCESS - Retrieves the device location successfully.
690 EFI_INVALID_PARAMETER - The Target or Lun is NULL.
694 SCSI_IO_DEV
*ScsiIoDevice
;
696 if (Target
== NULL
|| Lun
== NULL
) {
697 return EFI_INVALID_PARAMETER
;
700 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
702 CopyMem (*Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
704 *Lun
= ScsiIoDevice
->Lun
;
712 IN EFI_SCSI_IO_PROTOCOL
*This
718 Resets the SCSI Bus that the SCSI Controller is attached to.
722 This - Protocol instance pointer.
726 EFI_SUCCESS - The SCSI bus is reset successfully.
727 EFI_DEVICE_ERROR - Errors encountered when resetting the SCSI bus.
728 EFI_UNSUPPORTED - The bus reset operation is not supported by the
729 SCSI Host Controller.
730 EFI_TIMEOUT - A timeout occurred while attempting to reset
734 SCSI_IO_DEV
*ScsiIoDevice
;
736 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
738 if (ScsiIoDevice
->ExtScsiSupport
){
739 return ScsiIoDevice
->ExtScsiPassThru
->ResetChannel (ScsiIoDevice
->ExtScsiPassThru
);
741 return ScsiIoDevice
->ScsiPassThru
->ResetChannel (ScsiIoDevice
->ScsiPassThru
);
748 IN EFI_SCSI_IO_PROTOCOL
*This
754 Resets the SCSI Controller that the device handle specifies.
758 This - Protocol instance pointer.
762 EFI_SUCCESS - Reset the SCSI controller successfully.
763 EFI_DEVICE_ERROR - Errors are encountered when resetting the
765 EFI_UNSUPPORTED - The SCSI bus does not support a device
767 EFI_TIMEOUT - A timeout occurred while attempting to
768 reset the SCSI Controller.
771 SCSI_IO_DEV
*ScsiIoDevice
;
772 UINT8 Target
[TARGET_MAX_BYTES
];
774 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
775 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
778 if (ScsiIoDevice
->ExtScsiSupport
) {
779 return ScsiIoDevice
->ExtScsiPassThru
->ResetTargetLun (
780 ScsiIoDevice
->ExtScsiPassThru
,
785 return ScsiIoDevice
->ScsiPassThru
->ResetTarget (
786 ScsiIoDevice
->ScsiPassThru
,
787 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
795 ScsiExecuteSCSICommand (
796 IN EFI_SCSI_IO_PROTOCOL
*This
,
797 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
798 IN EFI_EVENT Event OPTIONAL
804 Sends a SCSI Request Packet to the SCSI Controller for execution.
808 This - Protocol instance pointer.
809 Packet - The SCSI request packet to send to the SCSI
810 Controller specified by the device handle.
811 Event - If the SCSI bus where the SCSI device is attached
812 does not support non-blocking I/O, then Event is
813 ignored, and blocking I/O is performed.
814 If Event is NULL, then blocking I/O is performed.
815 If Event is not NULL and non-blocking I/O is
816 supported, then non-blocking I/O is performed,
817 and Event will be signaled when the SCSI Request
821 EFI_SUCCESS - The SCSI Request Packet was sent by the host
822 successfully, and TransferLength bytes were
823 transferred to/from DataBuffer.See
824 HostAdapterStatus, TargetStatus,
825 SenseDataLength, and SenseData in that order
826 for additional status information.
827 EFI_BAD_BUFFER_SIZE - The SCSI Request Packet was executed,
828 but the entire DataBuffer could not be transferred.
829 The actual number of bytes transferred is returned
830 in TransferLength. See HostAdapterStatus,
831 TargetStatus, SenseDataLength, and SenseData in
832 that order for additional status information.
833 EFI_NOT_READY - The SCSI Request Packet could not be sent because
834 there are too many SCSI Command Packets already
835 queued.The caller may retry again later.
836 EFI_DEVICE_ERROR - A device error occurred while attempting to send
837 the SCSI Request Packet. See HostAdapterStatus,
838 TargetStatus, SenseDataLength, and SenseData in
839 that order for additional status information.
840 EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid.
841 The SCSI Request Packet was not sent, so no
842 additional status information is available.
843 EFI_UNSUPPORTED - The command described by the SCSI Request Packet
844 is not supported by the SCSI initiator(i.e., SCSI
845 Host Controller). The SCSI Request Packet was not
846 sent, so no additional status information is
848 EFI_TIMEOUT - A timeout occurred while waiting for the SCSI
849 Request Packet to execute. See HostAdapterStatus,
850 TargetStatus, SenseDataLength, and SenseData in
851 that order for additional status information.
854 SCSI_IO_DEV
*ScsiIoDevice
;
856 UINT8 Target
[TARGET_MAX_BYTES
];
857 EFI_EVENT PacketEvent
;
858 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ExtRequestPacket
;
859 SCSI_EVENT_DATA EventData
;
863 if (Packet
== NULL
) {
864 return EFI_INVALID_PARAMETER
;
867 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
868 CopyMem (Target
,&ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
870 if (ScsiIoDevice
->ExtScsiSupport
) {
871 ExtRequestPacket
= (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*) Packet
;
872 Status
= ScsiIoDevice
->ExtScsiPassThru
->PassThru (
873 ScsiIoDevice
->ExtScsiPassThru
,
881 Status
= gBS
->AllocatePool (
883 sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
),
884 (VOID
**)&WorkingBuffer
887 if (EFI_ERROR (Status
)) {
888 return EFI_DEVICE_ERROR
;
892 // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.
894 Status
= ScsiioToPassThruPacket(Packet
, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
);
895 if (EFI_ERROR(Status
)) {
896 gBS
->FreePool(WorkingBuffer
);
900 if ((ScsiIoDevice
->ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO
) && (Event
!= NULL
)) {
901 EventData
.Data1
= (VOID
*)Packet
;
902 EventData
.Data2
= Event
;
906 Status
= gBS
->CreateEvent (
913 if (EFI_ERROR(Status
)) {
914 gBS
->FreePool(WorkingBuffer
);
918 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
919 ScsiIoDevice
->ScsiPassThru
,
920 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
926 if (EFI_ERROR(Status
)) {
927 gBS
->FreePool(WorkingBuffer
);
928 gBS
->CloseEvent(PacketEvent
);
934 // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert
935 // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.
937 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
938 ScsiIoDevice
->ScsiPassThru
,
939 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
944 if (EFI_ERROR(Status
)) {
945 gBS
->FreePool(WorkingBuffer
);
949 PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
,Packet
);
951 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
952 // free WorkingBuffer.
954 gBS
->FreePool(WorkingBuffer
);
962 ScsiScanCreateDevice (
963 EFI_DRIVER_BINDING_PROTOCOL
*This
,
964 EFI_HANDLE Controller
,
965 SCSI_TARGET_ID
*TargetId
,
967 SCSI_BUS_DEVICE
*ScsiBusDev
973 Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.
977 This - Protocol instance pointer
978 Controller - Controller handle
979 Pun - The Pun of the SCSI device on the SCSI channel.
980 Lun - The Lun of the SCSI device on the SCSI channel.
981 ScsiBusDev - The pointer of SCSI_BUS_DEVICE
985 EFI_SUCCESS - Successfully to discover the device and attach ScsiIoProtocol to it.
986 EFI_OUT_OF_RESOURCES - Fail to discover the device.
991 SCSI_IO_DEV
*ScsiIoDevice
;
992 EFI_DEVICE_PATH_PROTOCOL
*ScsiDevicePath
;
994 Status
= gBS
->AllocatePool (
996 sizeof (SCSI_IO_DEV
),
997 (VOID
**) &ScsiIoDevice
999 if (EFI_ERROR (Status
)) {
1003 ZeroMem (ScsiIoDevice
, sizeof (SCSI_IO_DEV
));
1005 ScsiIoDevice
->Signature
= SCSI_IO_DEV_SIGNATURE
;
1006 CopyMem(&ScsiIoDevice
->Pun
, TargetId
, TARGET_MAX_BYTES
);
1007 ScsiIoDevice
->Lun
= Lun
;
1009 if (ScsiBusDev
->ExtScsiSupport
) {
1010 ScsiIoDevice
->ExtScsiPassThru
= ScsiBusDev
->ExtScsiInterface
;
1011 ScsiIoDevice
->ExtScsiSupport
= TRUE
;
1012 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ExtScsiPassThru
->Mode
->IoAlign
;
1015 ScsiIoDevice
->ScsiPassThru
= ScsiBusDev
->ScsiInterface
;
1016 ScsiIoDevice
->ExtScsiSupport
= FALSE
;
1017 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ScsiPassThru
->Mode
->IoAlign
;
1020 ScsiIoDevice
->ScsiIo
.GetDeviceType
= ScsiGetDeviceType
;
1021 ScsiIoDevice
->ScsiIo
.GetDeviceLocation
= ScsiGetDeviceLocation
;
1022 ScsiIoDevice
->ScsiIo
.ResetBus
= ScsiResetBus
;
1023 ScsiIoDevice
->ScsiIo
.ResetDevice
= ScsiResetDevice
;
1024 ScsiIoDevice
->ScsiIo
.ExecuteScsiCommand
= ScsiExecuteSCSICommand
;
1027 if (!DiscoverScsiDevice (ScsiIoDevice
)) {
1028 gBS
->FreePool (ScsiIoDevice
);
1029 return EFI_OUT_OF_RESOURCES
;
1035 if (ScsiIoDevice
->ExtScsiSupport
){
1036 Status
= ScsiIoDevice
->ExtScsiPassThru
->BuildDevicePath (
1037 ScsiIoDevice
->ExtScsiPassThru
,
1038 &ScsiIoDevice
->Pun
.ScsiId
.ExtScsi
[0],
1042 if (Status
== EFI_OUT_OF_RESOURCES
) {
1043 gBS
->FreePool (ScsiIoDevice
);
1047 Status
= ScsiIoDevice
->ScsiPassThru
->BuildDevicePath (
1048 ScsiIoDevice
->ScsiPassThru
,
1049 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
1053 if (Status
== EFI_OUT_OF_RESOURCES
) {
1054 gBS
->FreePool (ScsiIoDevice
);
1059 ScsiIoDevice
->DevicePath
= AppendDevicePathNode (
1060 ScsiBusDev
->DevicePath
,
1064 // The memory space for ScsiDevicePath is allocated in
1065 // ScsiPassThru->BuildDevicePath() function; It is no longer used
1066 // after EfiAppendDevicePathNode,so free the memory it occupies.
1068 gBS
->FreePool (ScsiDevicePath
);
1070 if (ScsiIoDevice
->DevicePath
== NULL
) {
1071 gBS
->FreePool (ScsiIoDevice
);
1072 return EFI_OUT_OF_RESOURCES
;
1075 Status
= gBS
->InstallMultipleProtocolInterfaces (
1076 &ScsiIoDevice
->Handle
,
1077 &gEfiDevicePathProtocolGuid
,
1078 ScsiIoDevice
->DevicePath
,
1079 &gEfiScsiIoProtocolGuid
,
1080 &ScsiIoDevice
->ScsiIo
,
1083 if (EFI_ERROR (Status
)) {
1084 gBS
->FreePool (ScsiIoDevice
);
1085 return EFI_OUT_OF_RESOURCES
;
1087 if (ScsiBusDev
->ExtScsiSupport
) {
1090 &gEfiExtScsiPassThruProtocolGuid
,
1091 (VOID
**) &(ScsiBusDev
->ExtScsiInterface
),
1092 This
->DriverBindingHandle
,
1093 ScsiIoDevice
->Handle
,
1094 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1099 &gEfiScsiPassThruProtocolGuid
,
1100 (VOID
**) &(ScsiBusDev
->ScsiInterface
),
1101 This
->DriverBindingHandle
,
1102 ScsiIoDevice
->Handle
,
1103 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1112 DiscoverScsiDevice (
1113 SCSI_IO_DEV
*ScsiIoDevice
1117 Routine Description:
1119 Discovery SCSI Device
1123 ScsiIoDevice - The pointer of SCSI_IO_DEV
1127 TRUE - Find SCSI Device and verify it.
1128 FALSE - Unable to find SCSI Device.
1133 UINT32 InquiryDataLength
;
1134 UINT8 SenseDataLength
;
1135 UINT8 HostAdapterStatus
;
1137 EFI_SCSI_SENSE_DATA SenseData
;
1138 EFI_SCSI_INQUIRY_DATA InquiryData
;
1140 HostAdapterStatus
= 0;
1143 // Using Inquiry command to scan for the device
1145 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1146 SenseDataLength
= sizeof (EFI_SCSI_SENSE_DATA
);
1148 Status
= ScsiInquiryCommand (
1149 &ScsiIoDevice
->ScsiIo
,
1150 EfiScsiStallSeconds (1),
1151 (VOID
*) &SenseData
,
1155 (VOID
*) &InquiryData
,
1159 if (EFI_ERROR (Status
)) {
1161 // ParseSenseData (&SenseData,SenseDataLength);
1166 // Retrieved inquiry data successfully
1168 if ((InquiryData
.Peripheral_Qualifier
!= 0) &&
1169 (InquiryData
.Peripheral_Qualifier
!= 3)) {
1173 if (InquiryData
.Peripheral_Qualifier
== 3) {
1174 if (InquiryData
.Peripheral_Type
!= 0x1f) {
1179 if (0x1e >= InquiryData
.Peripheral_Type
&& InquiryData
.Peripheral_Type
>= 0xa) {
1184 // valid device type and peripheral qualifier combination.
1186 ScsiIoDevice
->ScsiDeviceType
= InquiryData
.Peripheral_Type
;
1187 ScsiIoDevice
->RemovableDevice
= InquiryData
.RMB
;
1188 if (InquiryData
.Version
== 0) {
1189 ScsiIoDevice
->ScsiVersion
= 0;
1192 // ANSI-approved version
1194 ScsiIoDevice
->ScsiVersion
= (UINT8
) (InquiryData
.Version
& 0x03);
1203 ScsiioToPassThruPacket (
1204 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
1205 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
1209 Routine Description:
1211 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to
1212 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet
1216 Packet - The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1217 CommandPacket - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1226 //EFI 1.10 doesn't support Bi-Direction Command.
1228 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL
) {
1229 return EFI_UNSUPPORTED
;
1232 ZeroMem (CommandPacket
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1234 CommandPacket
->Timeout
= Packet
->Timeout
;
1235 CommandPacket
->Cdb
= Packet
->Cdb
;
1236 CommandPacket
->CdbLength
= Packet
->CdbLength
;
1237 CommandPacket
->DataDirection
= Packet
->DataDirection
;
1238 CommandPacket
->HostAdapterStatus
= Packet
->HostAdapterStatus
;
1239 CommandPacket
->TargetStatus
= Packet
->TargetStatus
;
1240 CommandPacket
->SenseData
= Packet
->SenseData
;
1241 CommandPacket
->SenseDataLength
= Packet
->SenseDataLength
;
1243 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1244 CommandPacket
->DataBuffer
= Packet
->InDataBuffer
;
1245 CommandPacket
->TransferLength
= Packet
->InTransferLength
;
1246 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1247 CommandPacket
->DataBuffer
= Packet
->OutDataBuffer
;
1248 CommandPacket
->TransferLength
= Packet
->OutTransferLength
;
1256 PassThruToScsiioPacket (
1257 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
1258 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
1262 Routine Description:
1264 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to
1265 EFI_SCSI_IO_SCSI_REQUEST_PACKET packet
1269 ScsiPacket - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1270 Packet - The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1278 Packet
->Timeout
= ScsiPacket
->Timeout
;
1279 Packet
->Cdb
= ScsiPacket
->Cdb
;
1280 Packet
->CdbLength
= ScsiPacket
->CdbLength
;
1281 Packet
->DataDirection
= ScsiPacket
->DataDirection
;
1282 Packet
->HostAdapterStatus
= ScsiPacket
->HostAdapterStatus
;
1283 Packet
->TargetStatus
= ScsiPacket
->TargetStatus
;
1284 Packet
->SenseData
= ScsiPacket
->SenseData
;
1285 Packet
->SenseDataLength
= ScsiPacket
->SenseDataLength
;
1287 if (ScsiPacket
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1288 Packet
->InDataBuffer
= ScsiPacket
->DataBuffer
;
1289 Packet
->InTransferLength
= ScsiPacket
->TransferLength
;
1290 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1291 Packet
->OutDataBuffer
= ScsiPacket
->DataBuffer
;
1292 Packet
->OutTransferLength
= ScsiPacket
->TransferLength
;
1308 Routine Description:
1310 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
1315 Event - The instance of EFI_EVENT.
1316 Context - The parameter passed in.
1324 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
;
1325 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
;
1326 EFI_EVENT CallerEvent
;
1327 SCSI_EVENT_DATA
*PassData
;
1329 PassData
= (SCSI_EVENT_DATA
*)Context
;
1330 Packet
= (EFI_SCSI_IO_SCSI_REQUEST_PACKET
*)PassData
->Data1
;
1331 ScsiPacket
= (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)WorkingBuffer
;
1334 // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.
1336 PassThruToScsiioPacket(ScsiPacket
, Packet
);
1339 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1340 // free WorkingBuffer.
1342 gBS
->FreePool(WorkingBuffer
);
1345 // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.
1347 CallerEvent
= PassData
->Data2
;
1348 gBS
->CloseEvent(Event
);
1349 gBS
->SignalEvent(CallerEvent
);