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 - 2019, Intel Corporation. All rights reserved.<BR>
6 Copyright (c) 1985 - 2022, American Megatrends International LLC.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
14 EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding
= {
15 SCSIBusDriverBindingSupported
,
16 SCSIBusDriverBindingStart
,
17 SCSIBusDriverBindingStop
,
26 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.
28 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
29 @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
34 ScsiioToPassThruPacket (
35 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
36 OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
40 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.
42 @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
43 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
48 PassThruToScsiioPacket (
49 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
50 OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
54 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
57 @param Event The instance of EFI_EVENT.
58 @param Context The parameter passed in.
69 Allocates an aligned buffer for SCSI device.
71 This function allocates an aligned buffer for the SCSI device to perform
72 SCSI pass through operations. The alignment requirement is from SCSI pass
75 @param ScsiIoDevice The SCSI child device involved for the operation.
76 @param BufferSize The request buffer size.
78 @return A pointer to the aligned buffer or NULL if the allocation fails.
82 AllocateAlignedBuffer (
83 IN SCSI_IO_DEV
*ScsiIoDevice
,
87 return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize
), ScsiIoDevice
->ScsiIo
.IoAlign
);
91 Frees an aligned buffer for SCSI device.
93 This function frees an aligned buffer for the SCSI device to perform
94 SCSI pass through operations.
96 @param Buffer The aligned buffer to be freed.
97 @param BufferSize The request buffer size.
106 if (Buffer
!= NULL
) {
107 FreeAlignedPages (Buffer
, EFI_SIZE_TO_PAGES (BufferSize
));
112 The user Entry Point for module ScsiBus. The user code starts with this function.
114 @param ImageHandle The firmware allocated handle for the EFI image.
115 @param SystemTable A pointer to the EFI System Table.
117 @retval EFI_SUCCESS The entry point is executed successfully.
118 @retval other Some error occurs when executing this entry point.
124 IN EFI_HANDLE ImageHandle
,
125 IN EFI_SYSTEM_TABLE
*SystemTable
131 // Install driver model protocol(s).
133 Status
= EfiLibInstallDriverBindingComponentName2 (
136 &gSCSIBusDriverBinding
,
138 &gScsiBusComponentName
,
139 &gScsiBusComponentName2
141 ASSERT_EFI_ERROR (Status
);
147 Test to see if this driver supports ControllerHandle.
149 This service is called by the EFI boot service ConnectController(). In order
150 to make drivers as small as possible, there are a few calling restrictions for
151 this service. ConnectController() must follow these calling restrictions. If
152 any other agent wishes to call Supported() it must also follow these calling
155 @param This Protocol instance pointer.
156 @param ControllerHandle Handle of device to test
157 @param RemainingDevicePath Optional parameter use to pick a specific child
160 @retval EFI_SUCCESS This driver supports this device
161 @retval EFI_ALREADY_STARTED This driver is already running on this device
162 @retval other This driver does not support this device
167 SCSIBusDriverBindingSupported (
168 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
169 IN EFI_HANDLE Controller
,
170 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
174 EFI_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
175 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtPassThru
;
178 SCSI_TARGET_ID ScsiTargetId
;
180 TargetId
= &ScsiTargetId
.ScsiId
.ExtScsi
[0];
181 SetMem (TargetId
, TARGET_MAX_BYTES
, 0xFF);
184 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
185 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
186 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
188 Status
= gBS
->OpenProtocol (
190 &gEfiExtScsiPassThruProtocolGuid
,
191 (VOID
**)&ExtPassThru
,
192 This
->DriverBindingHandle
,
194 EFI_OPEN_PROTOCOL_BY_DRIVER
197 if (Status
== EFI_ALREADY_STARTED
) {
199 } else if (!EFI_ERROR (Status
)) {
201 // Check if RemainingDevicePath is NULL or the End of Device Path Node,
202 // if yes, return EFI_SUCCESS.
204 if ((RemainingDevicePath
== NULL
) || IsDevicePathEnd (RemainingDevicePath
)) {
206 // Close protocol regardless of RemainingDevicePath validation
210 &gEfiExtScsiPassThruProtocolGuid
,
211 This
->DriverBindingHandle
,
217 // If RemainingDevicePath isn't the End of Device Path Node, check its validation
219 Status
= ExtPassThru
->GetTargetLun (ExtPassThru
, RemainingDevicePath
, &TargetId
, &Lun
);
221 // Close protocol regardless of RemainingDevicePath validation
225 &gEfiExtScsiPassThruProtocolGuid
,
226 This
->DriverBindingHandle
,
229 if (!EFI_ERROR (Status
)) {
236 // Come here in 2 condition:
237 // 1. ExtPassThru doesn't exist.
238 // 2. ExtPassThru exists but RemainingDevicePath is invalid.
240 Status
= gBS
->OpenProtocol (
242 &gEfiScsiPassThruProtocolGuid
,
244 This
->DriverBindingHandle
,
246 EFI_OPEN_PROTOCOL_BY_DRIVER
249 if (Status
== EFI_ALREADY_STARTED
) {
253 if (EFI_ERROR (Status
)) {
258 // Test RemainingDevicePath is valid or not.
260 if ((RemainingDevicePath
!= NULL
) && !IsDevicePathEnd (RemainingDevicePath
)) {
261 Status
= PassThru
->GetTargetLun (PassThru
, RemainingDevicePath
, &ScsiTargetId
.ScsiId
.Scsi
, &Lun
);
266 &gEfiScsiPassThruProtocolGuid
,
267 This
->DriverBindingHandle
,
274 Start this driver on ControllerHandle.
276 This service is called by the EFI boot service ConnectController(). In order
277 to make drivers as small as possible, there are a few calling restrictions for
278 this service. ConnectController() must follow these calling restrictions. If
279 any other agent wishes to call Start() it must also follow these calling
282 @param This Protocol instance pointer.
283 @param ControllerHandle Handle of device to bind driver to
284 @param RemainingDevicePath Optional parameter use to pick a specific child
287 @retval EFI_SUCCESS This driver is added to ControllerHandle
288 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
289 @retval other This driver does not support this device
294 SCSIBusDriverBindingStart (
295 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
296 IN EFI_HANDLE Controller
,
297 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
302 BOOLEAN ScanOtherPuns
;
303 BOOLEAN FromFirstTarget
;
304 BOOLEAN ExtScsiSupport
;
306 EFI_STATUS DevicePathStatus
;
307 EFI_STATUS PassThruStatus
;
308 SCSI_BUS_DEVICE
*ScsiBusDev
;
309 SCSI_TARGET_ID ScsiTargetId
;
310 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
311 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiInterface
;
312 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiInterface
;
313 EFI_SCSI_BUS_PROTOCOL
*BusIdentify
;
316 ScanOtherPuns
= TRUE
;
317 FromFirstTarget
= FALSE
;
318 ExtScsiSupport
= FALSE
;
319 PassThruStatus
= EFI_SUCCESS
;
321 TargetId
= &ScsiTargetId
.ScsiId
.ExtScsi
[0];
322 SetMem (TargetId
, TARGET_MAX_BYTES
, 0xFF);
324 DevicePathStatus
= gBS
->OpenProtocol (
326 &gEfiDevicePathProtocolGuid
,
327 (VOID
**)&ParentDevicePath
,
328 This
->DriverBindingHandle
,
330 EFI_OPEN_PROTOCOL_BY_DRIVER
332 if (EFI_ERROR (DevicePathStatus
) && (DevicePathStatus
!= EFI_ALREADY_STARTED
)) {
333 return DevicePathStatus
;
337 // Report Status Code to indicate SCSI bus starts
339 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
341 (EFI_IO_BUS_SCSI
| EFI_IOB_PC_INIT
),
346 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
347 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
348 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
350 Status
= gBS
->OpenProtocol (
352 &gEfiExtScsiPassThruProtocolGuid
,
353 (VOID
**)&ExtScsiInterface
,
354 This
->DriverBindingHandle
,
356 EFI_OPEN_PROTOCOL_BY_DRIVER
359 // Fail to open UEFI ExtendPassThru Protocol, then try to open EFI PassThru Protocol instead.
361 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
362 Status
= gBS
->OpenProtocol (
364 &gEfiScsiPassThruProtocolGuid
,
365 (VOID
**)&ScsiInterface
,
366 This
->DriverBindingHandle
,
368 EFI_OPEN_PROTOCOL_BY_DRIVER
371 // Fail to open EFI PassThru Protocol, Close the DevicePathProtocol if it is opened by this time.
373 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
374 if (!EFI_ERROR (DevicePathStatus
)) {
377 &gEfiDevicePathProtocolGuid
,
378 This
->DriverBindingHandle
,
387 // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol
388 // with BY_DRIVER if it is also present on the handle. The intent is to prevent
389 // another SCSI Bus Driver to work on the same host handle.
391 ExtScsiSupport
= TRUE
;
392 PassThruStatus
= gBS
->OpenProtocol (
394 &gEfiScsiPassThruProtocolGuid
,
395 (VOID
**)&ScsiInterface
,
396 This
->DriverBindingHandle
,
398 EFI_OPEN_PROTOCOL_BY_DRIVER
402 if (Status
!= EFI_ALREADY_STARTED
) {
404 // Go through here means either ExtPassThru or PassThru Protocol is successfully opened
405 // on this handle for this time. Then construct Host controller private data.
408 ScsiBusDev
= AllocateZeroPool (sizeof (SCSI_BUS_DEVICE
));
409 if (ScsiBusDev
== NULL
) {
410 Status
= EFI_OUT_OF_RESOURCES
;
414 ScsiBusDev
->Signature
= SCSI_BUS_DEVICE_SIGNATURE
;
415 ScsiBusDev
->ExtScsiSupport
= ExtScsiSupport
;
416 ScsiBusDev
->DevicePath
= ParentDevicePath
;
417 if (ScsiBusDev
->ExtScsiSupport
) {
418 ScsiBusDev
->ExtScsiInterface
= ExtScsiInterface
;
420 ScsiBusDev
->ScsiInterface
= ScsiInterface
;
424 // Install EFI_SCSI_BUS_PROTOCOL to the controller handle, So ScsiBusDev could be
425 // retrieved on this controller handle. With ScsiBusDev, we can know which PassThru
426 // Protocol is present on the handle, UEFI ExtPassThru Protocol or EFI PassThru Protocol.
428 Status
= gBS
->InstallProtocolInterface (
431 EFI_NATIVE_INTERFACE
,
432 &ScsiBusDev
->BusIdentify
434 if (EFI_ERROR (Status
)) {
439 // Go through here means Start() is re-invoked again, nothing special is required to do except
440 // picking up Host controller private information.
442 Status
= gBS
->OpenProtocol (
445 (VOID
**)&BusIdentify
,
446 This
->DriverBindingHandle
,
448 EFI_OPEN_PROTOCOL_GET_PROTOCOL
451 if (EFI_ERROR (Status
)) {
455 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify
);
459 // Report Status Code to indicate detecting devices on bus
461 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
463 (EFI_IO_BUS_SCSI
| EFI_IOB_PC_DETECT
),
468 if (RemainingDevicePath
== NULL
) {
470 // If RemainingDevicePath is NULL,
471 // must enumerate all SCSI devices anyway
473 FromFirstTarget
= TRUE
;
474 } else if (!IsDevicePathEnd (RemainingDevicePath
)) {
476 // If RemainingDevicePath isn't the End of Device Path Node,
477 // only scan the specified device by RemainingDevicePath
479 if (ScsiBusDev
->ExtScsiSupport
) {
480 Status
= ScsiBusDev
->ExtScsiInterface
->GetTargetLun (ScsiBusDev
->ExtScsiInterface
, RemainingDevicePath
, &TargetId
, &Lun
);
482 Status
= ScsiBusDev
->ScsiInterface
->GetTargetLun (ScsiBusDev
->ScsiInterface
, RemainingDevicePath
, &ScsiTargetId
.ScsiId
.Scsi
, &Lun
);
485 if (EFI_ERROR (Status
)) {
490 // If RemainingDevicePath is the End of Device Path Node,
491 // skip enumerate any device and return EFI_SUCCESS
493 ScanOtherPuns
= FALSE
;
496 while (ScanOtherPuns
) {
497 if (FromFirstTarget
) {
499 // Remaining Device Path is NULL, scan all the possible Puns in the
502 if (ScsiBusDev
->ExtScsiSupport
) {
503 Status
= ScsiBusDev
->ExtScsiInterface
->GetNextTargetLun (ScsiBusDev
->ExtScsiInterface
, &TargetId
, &Lun
);
505 Status
= ScsiBusDev
->ScsiInterface
->GetNextDevice (ScsiBusDev
->ScsiInterface
, &ScsiTargetId
.ScsiId
.Scsi
, &Lun
);
508 if (EFI_ERROR (Status
)) {
510 // no legal Pun and Lun found any more
515 ScanOtherPuns
= FALSE
;
519 // Avoid creating handle for the host adapter.
521 if (ScsiBusDev
->ExtScsiSupport
) {
522 if ((ScsiTargetId
.ScsiId
.Scsi
) == ScsiBusDev
->ExtScsiInterface
->Mode
->AdapterId
) {
526 if ((ScsiTargetId
.ScsiId
.Scsi
) == ScsiBusDev
->ScsiInterface
->Mode
->AdapterId
) {
532 // Scan for the scsi device, if it attaches to the scsi bus,
533 // then create handle and install scsi i/o protocol.
535 Status
= ScsiScanCreateDevice (This
, Controller
, &ScsiTargetId
, Lun
, ScsiBusDev
);
536 if (Status
== EFI_OUT_OF_RESOURCES
) {
545 if (ScsiBusDev
!= NULL
) {
546 FreePool (ScsiBusDev
);
549 if (ExtScsiSupport
) {
552 &gEfiExtScsiPassThruProtocolGuid
,
553 This
->DriverBindingHandle
,
556 if (!EFI_ERROR (PassThruStatus
)) {
559 &gEfiScsiPassThruProtocolGuid
,
560 This
->DriverBindingHandle
,
567 &gEfiScsiPassThruProtocolGuid
,
568 This
->DriverBindingHandle
,
577 Stop this driver on ControllerHandle.
579 This service is called by the EFI boot service DisconnectController().
580 In order to make drivers as small as possible, there are a few calling
581 restrictions for this service. DisconnectController() must follow these
582 calling restrictions. If any other agent wishes to call Stop() it must also
583 follow these calling restrictions.
585 @param This Protocol instance pointer.
586 @param ControllerHandle Handle of device to stop driver on
587 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
588 children is zero stop the entire bus driver.
589 @param ChildHandleBuffer List of Child Handles to Stop.
591 @retval EFI_SUCCESS This driver is removed ControllerHandle
592 @retval other This driver was not removed from this device
597 SCSIBusDriverBindingStop (
598 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
599 IN EFI_HANDLE Controller
,
600 IN UINTN NumberOfChildren
,
601 IN EFI_HANDLE
*ChildHandleBuffer
605 BOOLEAN AllChildrenStopped
;
607 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
608 SCSI_IO_DEV
*ScsiIoDevice
;
610 EFI_SCSI_BUS_PROTOCOL
*Scsidentifier
;
611 SCSI_BUS_DEVICE
*ScsiBusDev
;
613 if (NumberOfChildren
== 0) {
615 // Get the SCSI_BUS_DEVICE
617 Status
= gBS
->OpenProtocol (
620 (VOID
**)&Scsidentifier
,
621 This
->DriverBindingHandle
,
623 EFI_OPEN_PROTOCOL_GET_PROTOCOL
626 if (EFI_ERROR (Status
)) {
627 return EFI_DEVICE_ERROR
;
630 ScsiBusDev
= SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier
);
633 // Uninstall SCSI Bus Protocol
635 gBS
->UninstallProtocolInterface (
638 &ScsiBusDev
->BusIdentify
642 // Close the bus driver
644 if (ScsiBusDev
->ExtScsiSupport
) {
646 // Close ExtPassThru Protocol from this controller handle
650 &gEfiExtScsiPassThruProtocolGuid
,
651 This
->DriverBindingHandle
,
655 // When Start() succeeds to open ExtPassThru, it always tries to open PassThru BY_DRIVER.
656 // Its intent is to prevent another SCSI Bus Driver from working on the same host handle.
657 // So Stop() needs to try to close PassThru if present here.
661 &gEfiScsiPassThruProtocolGuid
,
662 This
->DriverBindingHandle
,
668 &gEfiScsiPassThruProtocolGuid
,
669 This
->DriverBindingHandle
,
676 &gEfiDevicePathProtocolGuid
,
677 This
->DriverBindingHandle
,
680 FreePool (ScsiBusDev
);
684 AllChildrenStopped
= TRUE
;
686 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
687 Status
= gBS
->OpenProtocol (
688 ChildHandleBuffer
[Index
],
689 &gEfiScsiIoProtocolGuid
,
691 This
->DriverBindingHandle
,
693 EFI_OPEN_PROTOCOL_GET_PROTOCOL
695 if (EFI_ERROR (Status
)) {
696 AllChildrenStopped
= FALSE
;
700 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (ScsiIo
);
702 // Close the child handle
704 if (ScsiIoDevice
->ExtScsiSupport
) {
705 Status
= gBS
->CloseProtocol (
707 &gEfiExtScsiPassThruProtocolGuid
,
708 This
->DriverBindingHandle
,
709 ChildHandleBuffer
[Index
]
712 Status
= gBS
->CloseProtocol (
714 &gEfiScsiPassThruProtocolGuid
,
715 This
->DriverBindingHandle
,
716 ChildHandleBuffer
[Index
]
720 Status
= gBS
->UninstallMultipleProtocolInterfaces (
721 ChildHandleBuffer
[Index
],
722 &gEfiDevicePathProtocolGuid
,
723 ScsiIoDevice
->DevicePath
,
724 &gEfiScsiIoProtocolGuid
,
725 &ScsiIoDevice
->ScsiIo
,
728 if (EFI_ERROR (Status
)) {
729 AllChildrenStopped
= FALSE
;
730 if (ScsiIoDevice
->ExtScsiSupport
) {
733 &gEfiExtScsiPassThruProtocolGuid
,
735 This
->DriverBindingHandle
,
736 ChildHandleBuffer
[Index
],
737 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
742 &gEfiScsiPassThruProtocolGuid
,
744 This
->DriverBindingHandle
,
745 ChildHandleBuffer
[Index
],
746 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
750 FreePool (ScsiIoDevice
);
754 if (!AllChildrenStopped
) {
755 return EFI_DEVICE_ERROR
;
762 Retrieves the device type information of the SCSI Controller.
764 @param This Protocol instance pointer.
765 @param DeviceType A pointer to the device type information retrieved from
768 @retval EFI_SUCCESS Retrieves the device type information successfully.
769 @retval EFI_INVALID_PARAMETER The DeviceType is NULL.
775 IN EFI_SCSI_IO_PROTOCOL
*This
,
776 OUT UINT8
*DeviceType
779 SCSI_IO_DEV
*ScsiIoDevice
;
781 if (DeviceType
== NULL
) {
782 return EFI_INVALID_PARAMETER
;
785 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
786 *DeviceType
= ScsiIoDevice
->ScsiDeviceType
;
791 Retrieves the device location in the SCSI channel.
793 @param This Protocol instance pointer.
794 @param Target A pointer to the Target ID of a SCSI device
796 @param Lun A pointer to the LUN of the SCSI device on
799 @retval EFI_SUCCESS Retrieves the device location successfully.
800 @retval EFI_INVALID_PARAMETER The Target or Lun is NULL.
805 ScsiGetDeviceLocation (
806 IN EFI_SCSI_IO_PROTOCOL
*This
,
807 IN OUT UINT8
**Target
,
811 SCSI_IO_DEV
*ScsiIoDevice
;
813 if ((Target
== NULL
) || (Lun
== NULL
)) {
814 return EFI_INVALID_PARAMETER
;
817 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
819 CopyMem (*Target
, &ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
821 *Lun
= ScsiIoDevice
->Lun
;
827 Resets the SCSI Bus that the SCSI Controller is attached to.
829 @param This Protocol instance pointer.
831 @retval EFI_SUCCESS The SCSI bus is reset successfully.
832 @retval EFI_DEVICE_ERROR Errors encountered when resetting the SCSI bus.
833 @retval EFI_UNSUPPORTED The bus reset operation is not supported by the
834 SCSI Host Controller.
835 @retval EFI_TIMEOUT A timeout occurred while attempting to reset
841 IN EFI_SCSI_IO_PROTOCOL
*This
844 SCSI_IO_DEV
*ScsiIoDevice
;
846 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
849 // Report Status Code to indicate reset happens
851 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
853 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_PC_RESET
),
854 ScsiIoDevice
->ScsiBusDeviceData
->DevicePath
857 if (ScsiIoDevice
->ExtScsiSupport
) {
858 return ScsiIoDevice
->ExtScsiPassThru
->ResetChannel (ScsiIoDevice
->ExtScsiPassThru
);
860 return ScsiIoDevice
->ScsiPassThru
->ResetChannel (ScsiIoDevice
->ScsiPassThru
);
865 Resets the SCSI Controller that the device handle specifies.
867 @param This Protocol instance pointer.
869 @retval EFI_SUCCESS Reset the SCSI controller successfully.
870 @retval EFI_DEVICE_ERROR Errors are encountered when resetting the SCSI Controller.
871 @retval EFI_UNSUPPORTED The SCSI bus does not support a device reset operation.
872 @retval EFI_TIMEOUT A timeout occurred while attempting to reset the
878 IN EFI_SCSI_IO_PROTOCOL
*This
881 SCSI_IO_DEV
*ScsiIoDevice
;
882 UINT8 Target
[TARGET_MAX_BYTES
];
884 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
887 // Report Status Code to indicate reset happens
889 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
891 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_PC_RESET
),
892 ScsiIoDevice
->ScsiBusDeviceData
->DevicePath
895 CopyMem (Target
, &ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
897 if (ScsiIoDevice
->ExtScsiSupport
) {
898 return ScsiIoDevice
->ExtScsiPassThru
->ResetTargetLun (
899 ScsiIoDevice
->ExtScsiPassThru
,
904 return ScsiIoDevice
->ScsiPassThru
->ResetTarget (
905 ScsiIoDevice
->ScsiPassThru
,
906 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
913 Sends a SCSI Request Packet to the SCSI Controller for execution.
915 @param This Protocol instance pointer.
916 @param CommandPacket The SCSI request packet to send to the SCSI
917 Controller specified by the device handle.
918 @param Event If the SCSI bus where the SCSI device is attached
919 does not support non-blocking I/O, then Event is
920 ignored, and blocking I/O is performed.
921 If Event is NULL, then blocking I/O is performed.
922 If Event is not NULL and non-blocking I/O is
923 supported, then non-blocking I/O is performed,
924 and Event will be signaled when the SCSI Request
927 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host
928 successfully, and TransferLength bytes were
929 transferred to/from DataBuffer.See
930 HostAdapterStatus, TargetStatus,
931 SenseDataLength, and SenseData in that order
932 for additional status information.
933 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
934 but the entire DataBuffer could not be transferred.
935 The actual number of bytes transferred is returned
936 in TransferLength. See HostAdapterStatus,
937 TargetStatus, SenseDataLength, and SenseData in
938 that order for additional status information.
939 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
940 there are too many SCSI Command Packets already
941 queued.The caller may retry again later.
942 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
943 the SCSI Request Packet. See HostAdapterStatus,
944 TargetStatus, SenseDataLength, and SenseData in
945 that order for additional status information.
946 @retval EFI_INVALID_PARAMETER The contents of CommandPacket are invalid.
947 The SCSI Request Packet was not sent, so no
948 additional status information is available.
949 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
950 is not supported by the SCSI initiator(i.e., SCSI
951 Host Controller). The SCSI Request Packet was not
952 sent, so no additional status information is
954 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
955 Request Packet to execute. See HostAdapterStatus,
956 TargetStatus, SenseDataLength, and SenseData in
957 that order for additional status information.
961 ScsiExecuteSCSICommand (
962 IN EFI_SCSI_IO_PROTOCOL
*This
,
963 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
964 IN EFI_EVENT Event OPTIONAL
967 SCSI_IO_DEV
*ScsiIoDevice
;
969 UINT8 Target
[TARGET_MAX_BYTES
];
970 EFI_EVENT PacketEvent
;
971 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ExtRequestPacket
;
972 SCSI_EVENT_DATA EventData
;
976 if (Packet
== NULL
) {
977 return EFI_INVALID_PARAMETER
;
980 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
981 CopyMem (Target
, &ScsiIoDevice
->Pun
, TARGET_MAX_BYTES
);
983 if (ScsiIoDevice
->ExtScsiSupport
) {
984 ExtRequestPacket
= (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)Packet
;
986 if (((ScsiIoDevice
->ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO
) != 0) && (Event
!= NULL
)) {
987 Status
= ScsiIoDevice
->ExtScsiPassThru
->PassThru (
988 ScsiIoDevice
->ExtScsiPassThru
,
996 // If there's no event or the SCSI Device doesn't support NON-BLOCKING,
997 // let the 'Event' parameter for PassThru() be NULL.
999 Status
= ScsiIoDevice
->ExtScsiPassThru
->PassThru (
1000 ScsiIoDevice
->ExtScsiPassThru
,
1006 if ((!EFI_ERROR (Status
)) && (Event
!= NULL
)) {
1008 // Signal Event to tell caller to pick up the SCSI IO packet if the
1009 // PassThru() succeeds.
1011 gBS
->SignalEvent (Event
);
1015 mWorkingBuffer
= AllocatePool (sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1017 if (mWorkingBuffer
== NULL
) {
1018 return EFI_DEVICE_ERROR
;
1022 // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.
1024 Status
= ScsiioToPassThruPacket (Packet
, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)mWorkingBuffer
);
1025 if (EFI_ERROR (Status
)) {
1026 FreePool (mWorkingBuffer
);
1030 if (((ScsiIoDevice
->ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO
) != 0) && (Event
!= NULL
)) {
1031 EventData
.Data1
= (VOID
*)Packet
;
1032 EventData
.Data2
= Event
;
1036 Status
= gBS
->CreateEvent (
1043 if (EFI_ERROR (Status
)) {
1044 FreePool (mWorkingBuffer
);
1048 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
1049 ScsiIoDevice
->ScsiPassThru
,
1050 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
1056 if (EFI_ERROR (Status
)) {
1057 FreePool (mWorkingBuffer
);
1058 gBS
->CloseEvent (PacketEvent
);
1063 // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert
1064 // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.
1066 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
1067 ScsiIoDevice
->ScsiPassThru
,
1068 ScsiIoDevice
->Pun
.ScsiId
.Scsi
,
1073 if (EFI_ERROR (Status
)) {
1074 FreePool (mWorkingBuffer
);
1078 PassThruToScsiioPacket ((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)mWorkingBuffer
, Packet
);
1080 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1081 // free mWorkingBuffer.
1083 FreePool (mWorkingBuffer
);
1086 // Signal Event to tell caller to pick up the SCSI IO Packet.
1088 if (Event
!= NULL
) {
1089 gBS
->SignalEvent (Event
);
1098 Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.
1100 @param This Protocol instance pointer
1101 @param Controller Controller handle
1102 @param TargetId Target to be scanned
1103 @param Lun The Lun of the SCSI device on the SCSI channel.
1104 @param ScsiBusDev The pointer of SCSI_BUS_DEVICE
1106 @retval EFI_SUCCESS Successfully to discover the device and attach
1107 ScsiIoProtocol to it.
1108 @retval EFI_NOT_FOUND Fail to discover the device.
1109 @retval EFI_OUT_OF_RESOURCES Fail to allocate memory resources.
1114 ScsiScanCreateDevice (
1115 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1116 IN EFI_HANDLE Controller
,
1117 IN SCSI_TARGET_ID
*TargetId
,
1119 IN OUT SCSI_BUS_DEVICE
*ScsiBusDev
1123 SCSI_IO_DEV
*ScsiIoDevice
;
1124 EFI_DEVICE_PATH_PROTOCOL
*ScsiDevicePath
;
1125 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1126 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
1127 EFI_HANDLE DeviceHandle
;
1130 RemainingDevicePath
= NULL
;
1131 ScsiDevicePath
= NULL
;
1132 ScsiIoDevice
= NULL
;
1135 // Build Device Path
1137 if (ScsiBusDev
->ExtScsiSupport
) {
1138 Status
= ScsiBusDev
->ExtScsiInterface
->BuildDevicePath (
1139 ScsiBusDev
->ExtScsiInterface
,
1140 &TargetId
->ScsiId
.ExtScsi
[0],
1145 Status
= ScsiBusDev
->ScsiInterface
->BuildDevicePath (
1146 ScsiBusDev
->ScsiInterface
,
1147 TargetId
->ScsiId
.Scsi
,
1153 if (EFI_ERROR (Status
)) {
1157 DevicePath
= AppendDevicePathNode (
1158 ScsiBusDev
->DevicePath
,
1162 if (DevicePath
== NULL
) {
1163 Status
= EFI_OUT_OF_RESOURCES
;
1167 DeviceHandle
= NULL
;
1168 RemainingDevicePath
= DevicePath
;
1169 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &RemainingDevicePath
, &DeviceHandle
);
1170 if (!EFI_ERROR (Status
) && (DeviceHandle
!= NULL
) && IsDevicePathEnd (RemainingDevicePath
)) {
1172 // The device has been started, directly return to fast boot.
1174 Status
= EFI_ALREADY_STARTED
;
1178 ScsiIoDevice
= AllocateZeroPool (sizeof (SCSI_IO_DEV
));
1179 if (ScsiIoDevice
== NULL
) {
1180 Status
= EFI_OUT_OF_RESOURCES
;
1184 ScsiIoDevice
->Signature
= SCSI_IO_DEV_SIGNATURE
;
1185 ScsiIoDevice
->ScsiBusDeviceData
= ScsiBusDev
;
1186 CopyMem (&ScsiIoDevice
->Pun
, TargetId
, TARGET_MAX_BYTES
);
1187 ScsiIoDevice
->Lun
= Lun
;
1189 if (ScsiBusDev
->ExtScsiSupport
) {
1190 ScsiIoDevice
->ExtScsiPassThru
= ScsiBusDev
->ExtScsiInterface
;
1191 ScsiIoDevice
->ExtScsiSupport
= TRUE
;
1192 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ExtScsiPassThru
->Mode
->IoAlign
;
1194 ScsiIoDevice
->ScsiPassThru
= ScsiBusDev
->ScsiInterface
;
1195 ScsiIoDevice
->ExtScsiSupport
= FALSE
;
1196 ScsiIoDevice
->ScsiIo
.IoAlign
= ScsiIoDevice
->ScsiPassThru
->Mode
->IoAlign
;
1199 ScsiIoDevice
->ScsiIo
.GetDeviceType
= ScsiGetDeviceType
;
1200 ScsiIoDevice
->ScsiIo
.GetDeviceLocation
= ScsiGetDeviceLocation
;
1201 ScsiIoDevice
->ScsiIo
.ResetBus
= ScsiResetBus
;
1202 ScsiIoDevice
->ScsiIo
.ResetDevice
= ScsiResetDevice
;
1203 ScsiIoDevice
->ScsiIo
.ExecuteScsiCommand
= ScsiExecuteSCSICommand
;
1206 // Report Status Code here since the new SCSI device will be discovered
1208 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1210 (EFI_IO_BUS_SCSI
| EFI_IOB_PC_ENABLE
),
1211 ScsiBusDev
->DevicePath
1214 Status
= DiscoverScsiDevice (ScsiIoDevice
);
1215 if (EFI_ERROR (Status
)) {
1219 ScsiIoDevice
->DevicePath
= DevicePath
;
1221 Status
= gBS
->InstallMultipleProtocolInterfaces (
1222 &ScsiIoDevice
->Handle
,
1223 &gEfiDevicePathProtocolGuid
,
1224 ScsiIoDevice
->DevicePath
,
1225 &gEfiScsiIoProtocolGuid
,
1226 &ScsiIoDevice
->ScsiIo
,
1229 if (EFI_ERROR (Status
)) {
1232 if (ScsiBusDev
->ExtScsiSupport
) {
1235 &gEfiExtScsiPassThruProtocolGuid
,
1236 (VOID
**)&(ScsiBusDev
->ExtScsiInterface
),
1237 This
->DriverBindingHandle
,
1238 ScsiIoDevice
->Handle
,
1239 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1244 &gEfiScsiPassThruProtocolGuid
,
1245 (VOID
**)&(ScsiBusDev
->ScsiInterface
),
1246 This
->DriverBindingHandle
,
1247 ScsiIoDevice
->Handle
,
1248 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1258 // The memory space for ScsiDevicePath is allocated in
1259 // ScsiPassThru->BuildDevicePath() function; It is no longer used
1260 // after AppendDevicePathNode,so free the memory it occupies.
1262 FreePool (ScsiDevicePath
);
1264 if (DevicePath
!= NULL
) {
1265 FreePool (DevicePath
);
1268 if (ScsiIoDevice
!= NULL
) {
1269 FreePool (ScsiIoDevice
);
1276 Discovery SCSI Device
1278 @param ScsiIoDevice The pointer of SCSI_IO_DEV
1280 @retval EFI_SUCCESS Find SCSI Device and verify it.
1281 @retval EFI_NOT_FOUND Unable to find SCSI Device.
1282 @retval EFI_OUT_OF_RESOURCES Fail to allocate memory resources.
1286 DiscoverScsiDevice (
1287 IN OUT SCSI_IO_DEV
*ScsiIoDevice
1291 UINT32 InquiryDataLength
;
1292 UINT8 SenseDataLength
;
1293 UINT8 HostAdapterStatus
;
1295 EFI_SCSI_INQUIRY_DATA
*InquiryData
;
1296 EFI_SCSI_SENSE_DATA
*SenseData
;
1300 HostAdapterStatus
= 0;
1304 InquiryData
= AllocateAlignedBuffer (ScsiIoDevice
, sizeof (EFI_SCSI_INQUIRY_DATA
));
1305 if (InquiryData
== NULL
) {
1306 Status
= EFI_OUT_OF_RESOURCES
;
1310 SenseData
= AllocateAlignedBuffer (
1312 sizeof (EFI_SCSI_SENSE_DATA
)
1314 if (SenseData
== NULL
) {
1315 Status
= EFI_OUT_OF_RESOURCES
;
1320 // Using Inquiry command to scan for the device
1322 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1323 SenseDataLength
= sizeof (EFI_SCSI_SENSE_DATA
);
1324 ZeroMem (InquiryData
, InquiryDataLength
);
1325 ZeroMem (SenseData
, SenseDataLength
);
1328 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1329 Status
= ScsiInquiryCommand (
1330 &ScsiIoDevice
->ScsiIo
,
1336 (VOID
*)InquiryData
,
1340 if (!EFI_ERROR (Status
)) {
1341 if ((HostAdapterStatus
== EFI_SCSI_IO_STATUS_HOST_ADAPTER_OK
) &&
1342 (TargetStatus
== EFI_SCSI_IO_STATUS_TARGET_CHECK_CONDITION
) &&
1343 (SenseData
->Error_Code
== 0x70) &&
1344 (SenseData
->Sense_Key
== EFI_SCSI_SK_ILLEGAL_REQUEST
))
1346 Status
= EFI_NOT_FOUND
;
1353 if ((Status
== EFI_BAD_BUFFER_SIZE
) ||
1354 (Status
== EFI_INVALID_PARAMETER
) ||
1355 (Status
== EFI_UNSUPPORTED
))
1357 Status
= EFI_NOT_FOUND
;
1362 if (Index
== MaxRetry
) {
1363 Status
= EFI_NOT_FOUND
;
1368 // Retrieved inquiry data successfully
1370 if (InquiryData
->Peripheral_Qualifier
!= 0) {
1371 Status
= EFI_NOT_FOUND
;
1375 if ((InquiryData
->Peripheral_Type
>= EFI_SCSI_TYPE_RESERVED_LOW
) &&
1376 (InquiryData
->Peripheral_Type
<= EFI_SCSI_TYPE_RESERVED_HIGH
))
1378 Status
= EFI_NOT_FOUND
;
1383 // valid device type and peripheral qualifier combination.
1385 ScsiIoDevice
->ScsiDeviceType
= InquiryData
->Peripheral_Type
;
1386 ScsiIoDevice
->RemovableDevice
= InquiryData
->Rmb
;
1387 if (InquiryData
->Version
== 0) {
1388 ScsiIoDevice
->ScsiVersion
= 0;
1391 // ANSI-approved version
1393 ScsiIoDevice
->ScsiVersion
= (UINT8
)(InquiryData
->Version
& 0x07);
1396 Status
= EFI_SUCCESS
;
1399 FreeAlignedBuffer (SenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
1400 FreeAlignedBuffer (InquiryData
, sizeof (EFI_SCSI_INQUIRY_DATA
));
1406 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.
1408 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1409 @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1414 ScsiioToPassThruPacket (
1415 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
1416 OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*CommandPacket
1420 // EFI 1.10 doesn't support Bi-Direction Command.
1422 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL
) {
1423 return EFI_UNSUPPORTED
;
1426 ZeroMem (CommandPacket
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1428 CommandPacket
->Timeout
= Packet
->Timeout
;
1429 CommandPacket
->Cdb
= Packet
->Cdb
;
1430 CommandPacket
->CdbLength
= Packet
->CdbLength
;
1431 CommandPacket
->DataDirection
= Packet
->DataDirection
;
1432 CommandPacket
->HostAdapterStatus
= Packet
->HostAdapterStatus
;
1433 CommandPacket
->TargetStatus
= Packet
->TargetStatus
;
1434 CommandPacket
->SenseData
= Packet
->SenseData
;
1435 CommandPacket
->SenseDataLength
= Packet
->SenseDataLength
;
1437 if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1438 CommandPacket
->DataBuffer
= Packet
->InDataBuffer
;
1439 CommandPacket
->TransferLength
= Packet
->InTransferLength
;
1440 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1441 CommandPacket
->DataBuffer
= Packet
->OutDataBuffer
;
1442 CommandPacket
->TransferLength
= Packet
->OutTransferLength
;
1449 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.
1451 @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1452 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1457 PassThruToScsiioPacket (
1458 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
,
1459 OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
1462 Packet
->Timeout
= ScsiPacket
->Timeout
;
1463 Packet
->Cdb
= ScsiPacket
->Cdb
;
1464 Packet
->CdbLength
= ScsiPacket
->CdbLength
;
1465 Packet
->DataDirection
= ScsiPacket
->DataDirection
;
1466 Packet
->HostAdapterStatus
= ScsiPacket
->HostAdapterStatus
;
1467 Packet
->TargetStatus
= ScsiPacket
->TargetStatus
;
1468 Packet
->SenseData
= ScsiPacket
->SenseData
;
1469 Packet
->SenseDataLength
= ScsiPacket
->SenseDataLength
;
1471 if (ScsiPacket
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_READ
) {
1472 Packet
->InDataBuffer
= ScsiPacket
->DataBuffer
;
1473 Packet
->InTransferLength
= ScsiPacket
->TransferLength
;
1474 } else if (Packet
->DataDirection
== EFI_SCSI_IO_DATA_DIRECTION_WRITE
) {
1475 Packet
->OutDataBuffer
= ScsiPacket
->DataBuffer
;
1476 Packet
->OutTransferLength
= ScsiPacket
->TransferLength
;
1483 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
1486 @param Event The instance of EFI_EVENT.
1487 @param Context The parameter passed in.
1497 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
;
1498 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*ScsiPacket
;
1499 EFI_EVENT CallerEvent
;
1500 SCSI_EVENT_DATA
*PassData
;
1502 PassData
= (SCSI_EVENT_DATA
*)Context
;
1503 Packet
= (EFI_SCSI_IO_SCSI_REQUEST_PACKET
*)PassData
->Data1
;
1504 ScsiPacket
= (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*)mWorkingBuffer
;
1507 // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.
1509 PassThruToScsiioPacket (ScsiPacket
, Packet
);
1512 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1513 // free mWorkingBuffer.
1515 gBS
->FreePool (mWorkingBuffer
);
1518 // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.
1520 CallerEvent
= PassData
->Data2
;
1521 gBS
->CloseEvent (Event
);
1522 gBS
->SignalEvent (CallerEvent
);