3 Copyright (c) 2014 - 2017, Intel Corporation. All rights reserved.<BR>
4 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.
14 #include "UfsPassThru.h"
17 // Template for Ufs Pass Thru private data.
19 UFS_PASS_THRU_PRIVATE_DATA gUfsPassThruTemplate
= {
20 UFS_PASS_THRU_SIG
, // Signature
22 { // ExtScsiPassThruMode
24 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
| EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
| EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO
,
30 UfsPassThruGetNextTargetLun
,
31 UfsPassThruBuildDevicePath
,
32 UfsPassThruGetTargetLun
,
33 UfsPassThruResetChannel
,
34 UfsPassThruResetTargetLun
,
35 UfsPassThruGetNextTarget
42 0, // UfsHostController
54 UFS_LUN_0
, // Ufs Common Lun 0
55 UFS_LUN_1
, // Ufs Common Lun 1
56 UFS_LUN_2
, // Ufs Common Lun 2
57 UFS_LUN_3
, // Ufs Common Lun 3
58 UFS_LUN_4
, // Ufs Common Lun 4
59 UFS_LUN_5
, // Ufs Common Lun 5
60 UFS_LUN_6
, // Ufs Common Lun 6
61 UFS_LUN_7
, // Ufs Common Lun 7
62 UFS_WLUN_REPORT_LUNS
, // Ufs Reports Luns Well Known Lun
63 UFS_WLUN_UFS_DEV
, // Ufs Device Well Known Lun
64 UFS_WLUN_BOOT
, // Ufs Boot Well Known Lun
65 UFS_WLUN_RPMB
// RPMB Well Known Lun
67 0x0000, // By default don't expose any Luns.
77 EFI_DRIVER_BINDING_PROTOCOL gUfsPassThruDriverBinding
= {
78 UfsPassThruDriverBindingSupported
,
79 UfsPassThruDriverBindingStart
,
80 UfsPassThruDriverBindingStop
,
86 UFS_DEVICE_PATH mUfsDevicePathTemplate
= {
88 MESSAGING_DEVICE_PATH
,
91 (UINT8
) (sizeof (UFS_DEVICE_PATH
)),
92 (UINT8
) ((sizeof (UFS_DEVICE_PATH
)) >> 8)
99 UINT8 mUfsTargetId
[TARGET_MAX_BYTES
];
102 Sends a SCSI Request Packet to a SCSI device that is attached to the SCSI channel. This function
103 supports both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the
104 nonblocking I/O functionality is optional.
106 @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
107 @param Target The Target is an array of size TARGET_MAX_BYTES and it represents
108 the id of the SCSI device to send the SCSI Request Packet. Each
109 transport driver may choose to utilize a subset of this size to suit the needs
110 of transport target representation. For example, a Fibre Channel driver
111 may use only 8 bytes (WWN) to represent an FC target.
112 @param Lun The LUN of the SCSI device to send the SCSI Request Packet.
113 @param Packet A pointer to the SCSI Request Packet to send to the SCSI device
114 specified by Target and Lun.
115 @param Event If nonblocking I/O is not supported then Event is ignored, and blocking
116 I/O is performed. If Event is NULL, then blocking I/O is performed. If
117 Event is not NULL and non blocking I/O is supported, then
118 nonblocking I/O is performed, and Event will be signaled when the
119 SCSI Request Packet completes.
121 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
122 commands, InTransferLength bytes were transferred from
123 InDataBuffer. For write and bi-directional commands,
124 OutTransferLength bytes were transferred by
126 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was not executed. The number of bytes that
127 could be transferred is returned in InTransferLength. For write
128 and bi-directional commands, OutTransferLength bytes were
129 transferred by OutDataBuffer.
130 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
131 SCSI Request Packets already queued. The caller may retry again later.
132 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
134 @retval EFI_INVALID_PARAMETER Target, Lun, or the contents of ScsiRequestPacket are invalid.
135 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported
136 by the host adapter. This includes the case of Bi-directional SCSI
137 commands not supported by the implementation. The SCSI Request
138 Packet was not sent, so no additional status information is available.
139 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
144 UfsPassThruPassThru (
145 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
148 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
149 IN EFI_EVENT Event OPTIONAL
153 UFS_PASS_THRU_PRIVATE_DATA
*Private
;
157 Private
= UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS (This
);
159 if ((Packet
== NULL
) || (Packet
->Cdb
== NULL
)) {
160 return EFI_INVALID_PARAMETER
;
164 // Don't support variable length CDB
166 if ((Packet
->CdbLength
!= 6) && (Packet
->CdbLength
!= 10) &&
167 (Packet
->CdbLength
!= 12) && (Packet
->CdbLength
!= 16)) {
168 return EFI_INVALID_PARAMETER
;
171 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
== NULL
)) {
172 return EFI_INVALID_PARAMETER
;
175 if ((This
->Mode
->IoAlign
> 1) && !IS_ALIGNED(Packet
->InDataBuffer
, This
->Mode
->IoAlign
)) {
176 return EFI_INVALID_PARAMETER
;
179 if ((This
->Mode
->IoAlign
> 1) && !IS_ALIGNED(Packet
->OutDataBuffer
, This
->Mode
->IoAlign
)) {
180 return EFI_INVALID_PARAMETER
;
183 if ((This
->Mode
->IoAlign
> 1) && !IS_ALIGNED(Packet
->SenseData
, This
->Mode
->IoAlign
)) {
184 return EFI_INVALID_PARAMETER
;
188 // For UFS 2.0 compatible device, 0 is always used to represent the location of the UFS device.
190 SetMem (mUfsTargetId
, TARGET_MAX_BYTES
, 0x00);
191 if ((Target
== NULL
) || (CompareMem(Target
, mUfsTargetId
, TARGET_MAX_BYTES
) != 0)) {
192 return EFI_INVALID_PARAMETER
;
196 // UFS 2.0 spec Section 10.6.7 - Translation of 8-bit UFS LUN to 64-bit SCSI LUN Address
197 // 0xC1 in the first 8 bits of the 64-bit address indicates a well known LUN address in the SAM SCSI format.
198 // The second 8 bits of the 64-bit address saves the corresponding 8-bit UFS LUN.
200 if ((UINT8
)Lun
== UFS_WLUN_PREFIX
) {
201 UfsLun
= BIT7
| (((UINT8
*)&Lun
)[1] & 0xFF);
202 } else if ((UINT8
)Lun
== 0) {
203 UfsLun
= ((UINT8
*)&Lun
)[1] & 0xFF;
205 return EFI_INVALID_PARAMETER
;
208 for (Index
= 0; Index
< UFS_MAX_LUNS
; Index
++) {
209 if ((Private
->Luns
.BitMask
& (BIT0
<< Index
)) == 0) {
213 if (Private
->Luns
.Lun
[Index
] == UfsLun
) {
218 if (Index
== UFS_MAX_LUNS
) {
219 return EFI_INVALID_PARAMETER
;
222 Status
= UfsExecScsiCmds (Private
, UfsLun
, Packet
, Event
);
228 Used to retrieve the list of legal Target IDs and LUNs for SCSI devices on a SCSI channel. These
229 can either be the list SCSI devices that are actually present on the SCSI channel, or the list of legal
230 Target Ids and LUNs for the SCSI channel. Regardless, the caller of this function must probe the
231 Target ID and LUN returned to see if a SCSI device is actually present at that location on the SCSI
234 @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
235 @param Target On input, a pointer to the Target ID (an array of size
236 TARGET_MAX_BYTES) of a SCSI device present on the SCSI channel.
237 On output, a pointer to the Target ID (an array of
238 TARGET_MAX_BYTES) of the next SCSI device present on a SCSI
239 channel. An input value of 0xF(all bytes in the array are 0xF) in the
240 Target array retrieves the Target ID of the first SCSI device present on a
242 @param Lun On input, a pointer to the LUN of a SCSI device present on the SCSI
243 channel. On output, a pointer to the LUN of the next SCSI device present
246 @retval EFI_SUCCESS The Target ID and LUN of the next SCSI device on the SCSI
247 channel was returned in Target and Lun.
248 @retval EFI_INVALID_PARAMETER Target array is not all 0xF, and Target and Lun were
249 not returned on a previous call to GetNextTargetLun().
250 @retval EFI_NOT_FOUND There are no more SCSI devices on this SCSI channel.
255 UfsPassThruGetNextTargetLun (
256 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
257 IN OUT UINT8
**Target
,
261 UFS_PASS_THRU_PRIVATE_DATA
*Private
;
266 Private
= UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS (This
);
268 if (Target
== NULL
|| Lun
== NULL
) {
269 return EFI_INVALID_PARAMETER
;
272 if (*Target
== NULL
) {
273 return EFI_INVALID_PARAMETER
;
277 SetMem (mUfsTargetId
, TARGET_MAX_BYTES
, 0xFF);
278 if (CompareMem (*Target
, mUfsTargetId
, TARGET_MAX_BYTES
) == 0) {
280 // If the array is all 0xFF's, return the first exposed Lun to caller.
282 SetMem (*Target
, TARGET_MAX_BYTES
, 0x00);
283 for (Index
= 0; Index
< UFS_MAX_LUNS
; Index
++) {
284 if ((Private
->Luns
.BitMask
& (BIT0
<< Index
)) != 0) {
285 UfsLun
= Private
->Luns
.Lun
[Index
];
289 if (Index
!= UFS_MAX_LUNS
) {
291 if ((UfsLun
& BIT7
) == BIT7
) {
292 ((UINT8
*)Lun
)[0] = UFS_WLUN_PREFIX
;
293 ((UINT8
*)Lun
)[1] = UfsLun
& ~BIT7
;
295 ((UINT8
*)Lun
)[1] = UfsLun
;
299 return EFI_NOT_FOUND
;
303 SetMem (mUfsTargetId
, TARGET_MAX_BYTES
, 0x00);
304 if (CompareMem (*Target
, mUfsTargetId
, TARGET_MAX_BYTES
) == 0) {
305 if (((UINT8
*)Lun
)[0] == UFS_WLUN_PREFIX
) {
306 UfsLun
= BIT7
| (((UINT8
*)Lun
)[1] & 0xFF);
307 } else if (((UINT8
*)Lun
)[0] == 0) {
308 UfsLun
= ((UINT8
*)Lun
)[1] & 0xFF;
310 return EFI_NOT_FOUND
;
313 for (Index
= 0; Index
< UFS_MAX_LUNS
; Index
++) {
314 if ((Private
->Luns
.BitMask
& (BIT0
<< Index
)) == 0) {
318 if (Private
->Luns
.Lun
[Index
] != UfsLun
) {
322 for (Next
= Index
+ 1; Next
< UFS_MAX_LUNS
; Next
++) {
323 if ((Private
->Luns
.BitMask
& (BIT0
<< Next
)) != 0) {
324 UfsLun
= Private
->Luns
.Lun
[Next
];
329 if (Next
== UFS_MAX_LUNS
) {
330 return EFI_NOT_FOUND
;
336 if (Index
!= UFS_MAX_LUNS
) {
338 if ((UfsLun
& BIT7
) == BIT7
) {
339 ((UINT8
*)Lun
)[0] = UFS_WLUN_PREFIX
;
340 ((UINT8
*)Lun
)[1] = UfsLun
& ~BIT7
;
342 ((UINT8
*)Lun
)[1] = UfsLun
;
346 return EFI_NOT_FOUND
;
350 return EFI_NOT_FOUND
;
354 Used to allocate and build a device path node for a SCSI device on a SCSI channel.
356 @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
357 @param Target The Target is an array of size TARGET_MAX_BYTES and it specifies the
358 Target ID of the SCSI device for which a device path node is to be
359 allocated and built. Transport drivers may chose to utilize a subset of
360 this size to suit the representation of targets. For example, a Fibre
361 Channel driver may use only 8 bytes (WWN) in the array to represent a
363 @param Lun The LUN of the SCSI device for which a device path node is to be
365 @param DevicePath A pointer to a single device path node that describes the SCSI device
366 specified by Target and Lun. This function is responsible for
367 allocating the buffer DevicePath with the boot service
368 AllocatePool(). It is the caller's responsibility to free
369 DevicePath when the caller is finished with DevicePath.
371 @retval EFI_SUCCESS The device path node that describes the SCSI device specified by
372 Target and Lun was allocated and returned in
374 @retval EFI_INVALID_PARAMETER DevicePath is NULL.
375 @retval EFI_NOT_FOUND The SCSI devices specified by Target and Lun does not exist
377 @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate DevicePath.
382 UfsPassThruBuildDevicePath (
383 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
386 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
389 UFS_PASS_THRU_PRIVATE_DATA
*Private
;
390 EFI_DEV_PATH
*DevicePathNode
;
394 Private
= UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS (This
);
397 // Validate parameters passed in.
399 SetMem (mUfsTargetId
, TARGET_MAX_BYTES
, 0x00);
400 if (CompareMem (Target
, mUfsTargetId
, TARGET_MAX_BYTES
) != 0) {
401 return EFI_INVALID_PARAMETER
;
404 if ((UINT8
)Lun
== UFS_WLUN_PREFIX
) {
405 UfsLun
= BIT7
| (((UINT8
*)&Lun
)[1] & 0xFF);
406 } else if ((UINT8
)Lun
== 0) {
407 UfsLun
= ((UINT8
*)&Lun
)[1] & 0xFF;
409 return EFI_NOT_FOUND
;
412 for (Index
= 0; Index
< UFS_MAX_LUNS
; Index
++) {
413 if ((Private
->Luns
.BitMask
& (BIT0
<< Index
)) == 0) {
417 if (Private
->Luns
.Lun
[Index
] == UfsLun
) {
422 if (Index
== UFS_MAX_LUNS
) {
423 return EFI_NOT_FOUND
;
426 DevicePathNode
= AllocateCopyPool (sizeof (UFS_DEVICE_PATH
), &mUfsDevicePathTemplate
);
427 if (DevicePathNode
== NULL
) {
428 return EFI_OUT_OF_RESOURCES
;
431 DevicePathNode
->Ufs
.Pun
= 0;
432 DevicePathNode
->Ufs
.Lun
= UfsLun
;
434 *DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) DevicePathNode
;
440 Used to translate a device path node to a Target ID and LUN.
442 @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
443 @param DevicePath A pointer to a single device path node that describes the SCSI device
445 @param Target A pointer to the Target Array which represents the ID of a SCSI device
447 @param Lun A pointer to the LUN of a SCSI device on the SCSI channel.
449 @retval EFI_SUCCESS DevicePath was successfully translated to a Target ID and
450 LUN, and they were returned in Target and Lun.
451 @retval EFI_INVALID_PARAMETER DevicePath or Target or Lun is NULL.
452 @retval EFI_NOT_FOUND A valid translation from DevicePath to a Target ID and LUN
454 @retval EFI_UNSUPPORTED This driver does not support the device path node type in
460 UfsPassThruGetTargetLun (
461 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
462 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
467 UFS_PASS_THRU_PRIVATE_DATA
*Private
;
468 EFI_DEV_PATH
*DevicePathNode
;
473 Private
= UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS (This
);
476 // Validate parameters passed in.
478 if (DevicePath
== NULL
|| Target
== NULL
|| Lun
== NULL
) {
479 return EFI_INVALID_PARAMETER
;
482 if (*Target
== NULL
) {
483 return EFI_INVALID_PARAMETER
;
487 // Check whether the DevicePath belongs to UFS_DEVICE_PATH
489 if ((DevicePath
->Type
!= MESSAGING_DEVICE_PATH
) || (DevicePath
->SubType
!= MSG_UFS_DP
) ||
490 (DevicePathNodeLength(DevicePath
) != sizeof(UFS_DEVICE_PATH
))) {
491 return EFI_UNSUPPORTED
;
494 DevicePathNode
= (EFI_DEV_PATH
*) DevicePath
;
496 Pun
= (UINT8
) DevicePathNode
->Ufs
.Pun
;
497 UfsLun
= (UINT8
) DevicePathNode
->Ufs
.Lun
;
500 return EFI_NOT_FOUND
;
503 for (Index
= 0; Index
< UFS_MAX_LUNS
; Index
++) {
504 if ((Private
->Luns
.BitMask
& (BIT0
<< Index
)) == 0) {
508 if (Private
->Luns
.Lun
[Index
] == UfsLun
) {
513 if (Index
== UFS_MAX_LUNS
) {
514 return EFI_NOT_FOUND
;
517 SetMem (*Target
, TARGET_MAX_BYTES
, 0x00);
519 if ((UfsLun
& BIT7
) == BIT7
) {
520 ((UINT8
*)Lun
)[0] = UFS_WLUN_PREFIX
;
521 ((UINT8
*)Lun
)[1] = UfsLun
& ~BIT7
;
523 ((UINT8
*)Lun
)[1] = UfsLun
;
529 Resets a SCSI channel. This operation resets all the SCSI devices connected to the SCSI channel.
531 @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
533 @retval EFI_SUCCESS The SCSI channel was reset.
534 @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the SCSI channel.
535 @retval EFI_TIMEOUT A timeout occurred while attempting to reset the SCSI channel.
536 @retval EFI_UNSUPPORTED The SCSI channel does not support a channel reset operation.
541 UfsPassThruResetChannel (
542 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
546 // Return success directly then upper layer driver could think reset channel operation is done.
552 Resets a SCSI logical unit that is connected to a SCSI channel.
554 @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
555 @param Target The Target is an array of size TARGET_MAX_BYTE and it represents the
556 target port ID of the SCSI device containing the SCSI logical unit to
557 reset. Transport drivers may chose to utilize a subset of this array to suit
558 the representation of their targets.
559 @param Lun The LUN of the SCSI device to reset.
561 @retval EFI_SUCCESS The SCSI device specified by Target and Lun was reset.
562 @retval EFI_INVALID_PARAMETER Target or Lun is NULL.
563 @retval EFI_TIMEOUT A timeout occurred while attempting to reset the SCSI device
564 specified by Target and Lun.
565 @retval EFI_UNSUPPORTED The SCSI channel does not support a target reset operation.
566 @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the SCSI device
567 specified by Target and Lun.
572 UfsPassThruResetTargetLun (
573 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
579 // Return success directly then upper layer driver could think reset target LUN operation is done.
585 Used to retrieve the list of legal Target IDs for SCSI devices on a SCSI channel. These can either
586 be the list SCSI devices that are actually present on the SCSI channel, or the list of legal Target IDs
587 for the SCSI channel. Regardless, the caller of this function must probe the Target ID returned to
588 see if a SCSI device is actually present at that location on the SCSI channel.
590 @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
591 @param Target (TARGET_MAX_BYTES) of a SCSI device present on the SCSI channel.
592 On output, a pointer to the Target ID (an array of
593 TARGET_MAX_BYTES) of the next SCSI device present on a SCSI
594 channel. An input value of 0xF(all bytes in the array are 0xF) in the
595 Target array retrieves the Target ID of the first SCSI device present on a
598 @retval EFI_SUCCESS The Target ID of the next SCSI device on the SCSI
599 channel was returned in Target.
600 @retval EFI_INVALID_PARAMETER Target or Lun is NULL.
601 @retval EFI_TIMEOUT Target array is not all 0xF, and Target was not
602 returned on a previous call to GetNextTarget().
603 @retval EFI_NOT_FOUND There are no more SCSI devices on this SCSI channel.
608 UfsPassThruGetNextTarget (
609 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
610 IN OUT UINT8
**Target
613 if (Target
== NULL
|| *Target
== NULL
) {
614 return EFI_INVALID_PARAMETER
;
617 SetMem (mUfsTargetId
, TARGET_MAX_BYTES
, 0xFF);
618 if (CompareMem(*Target
, mUfsTargetId
, TARGET_MAX_BYTES
) == 0) {
619 SetMem (*Target
, TARGET_MAX_BYTES
, 0x00);
623 return EFI_NOT_FOUND
;
627 Tests to see if this driver supports a given controller. If a child device is provided,
628 it further tests to see if this driver supports creating a handle for the specified child device.
630 This function checks to see if the driver specified by This supports the device specified by
631 ControllerHandle. Drivers will typically use the device path attached to
632 ControllerHandle and/or the services from the bus I/O abstraction attached to
633 ControllerHandle to determine if the driver supports ControllerHandle. This function
634 may be called many times during platform initialization. In order to reduce boot times, the tests
635 performed by this function must be very small, and take as little time as possible to execute. This
636 function must not change the state of any hardware devices, and this function must be aware that the
637 device specified by ControllerHandle may already be managed by the same driver or a
638 different driver. This function must match its calls to AllocatePages() with FreePages(),
639 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
640 Since ControllerHandle may have been previously started by the same driver, if a protocol is
641 already in the opened state, then it must not be closed with CloseProtocol(). This is required
642 to guarantee the state of ControllerHandle is not modified by this function.
644 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
645 @param[in] ControllerHandle The handle of the controller to test. This handle
646 must support a protocol interface that supplies
647 an I/O abstraction to the driver.
648 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
649 parameter is ignored by device drivers, and is optional for bus
650 drivers. For bus drivers, if this parameter is not NULL, then
651 the bus driver must determine if the bus controller specified
652 by ControllerHandle and the child controller specified
653 by RemainingDevicePath are both supported by this
656 @retval EFI_SUCCESS The device specified by ControllerHandle and
657 RemainingDevicePath is supported by the driver specified by This.
658 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
659 RemainingDevicePath is already being managed by the driver
661 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
662 RemainingDevicePath is already being managed by a different
663 driver or an application that requires exclusive access.
664 Currently not implemented.
665 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
666 RemainingDevicePath is not supported by the driver specified by This.
670 UfsPassThruDriverBindingSupported (
671 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
672 IN EFI_HANDLE Controller
,
673 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
677 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
678 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHostController
;
681 // Ufs Pass Thru driver is a device driver, and should ingore the
682 // "RemainingDevicePath" according to UEFI spec
684 Status
= gBS
->OpenProtocol (
686 &gEfiDevicePathProtocolGuid
,
687 (VOID
*) &ParentDevicePath
,
688 This
->DriverBindingHandle
,
690 EFI_OPEN_PROTOCOL_BY_DRIVER
692 if (EFI_ERROR (Status
)) {
694 // EFI_ALREADY_STARTED is also an error
699 // Close the protocol because we don't use it here
703 &gEfiDevicePathProtocolGuid
,
704 This
->DriverBindingHandle
,
708 Status
= gBS
->OpenProtocol (
710 &gEdkiiUfsHostControllerProtocolGuid
,
711 (VOID
**) &UfsHostController
,
712 This
->DriverBindingHandle
,
714 EFI_OPEN_PROTOCOL_BY_DRIVER
717 if (EFI_ERROR (Status
)) {
719 // EFI_ALREADY_STARTED is also an error
725 // Close the I/O Abstraction(s) used to perform the supported test
729 &gEdkiiUfsHostControllerProtocolGuid
,
730 This
->DriverBindingHandle
,
738 Finishes device initialization by setting fDeviceInit flag and waiting untill device responds by
741 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
743 @retval EFI_SUCCESS The operation succeeds.
744 @retval Others The operation fails.
748 UfsFinishDeviceInitialization (
749 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
753 UINT8 DeviceInitStatus
;
756 DeviceInitStatus
= 0xFF;
759 // The host enables the device initialization completion by setting fDeviceInit flag.
761 Status
= UfsSetFlag (Private
, UfsFlagDevInit
);
762 if (EFI_ERROR (Status
)) {
768 Status
= UfsReadFlag (Private
, UfsFlagDevInit
, &DeviceInitStatus
);
769 if (EFI_ERROR (Status
)) {
772 MicroSecondDelay (1);
774 } while (DeviceInitStatus
!= 0 && Timeout
!= 0);
780 Starts a device controller or a bus controller.
782 The Start() function is designed to be invoked from the EFI boot service ConnectController().
783 As a result, much of the error checking on the parameters to Start() has been moved into this
784 common boot service. It is legal to call Start() from other locations,
785 but the following calling restrictions must be followed or the system behavior will not be deterministic.
786 1. ControllerHandle must be a valid EFI_HANDLE.
787 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
788 EFI_DEVICE_PATH_PROTOCOL.
789 3. Prior to calling Start(), the Supported() function for the driver specified by This must
790 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
792 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
793 @param[in] ControllerHandle The handle of the controller to start. This handle
794 must support a protocol interface that supplies
795 an I/O abstraction to the driver.
796 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
797 parameter is ignored by device drivers, and is optional for bus
798 drivers. For a bus driver, if this parameter is NULL, then handles
799 for all the children of Controller are created by this driver.
800 If this parameter is not NULL and the first Device Path Node is
801 not the End of Device Path Node, then only the handle for the
802 child device specified by the first Device Path Node of
803 RemainingDevicePath is created by this driver.
804 If the first Device Path Node of RemainingDevicePath is
805 the End of Device Path Node, no child handle is created by this
808 @retval EFI_SUCCESS The device was started.
809 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
810 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
811 @retval Others The driver failded to start the device.
816 UfsPassThruDriverBindingStart (
817 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
818 IN EFI_HANDLE Controller
,
819 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
823 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
824 UFS_PASS_THRU_PRIVATE_DATA
*Private
;
827 UFS_UNIT_DESC UnitDescriptor
;
828 UINT32 UnitDescriptorSize
;
830 Status
= EFI_SUCCESS
;
835 DEBUG ((DEBUG_INFO
, "==UfsPassThru Start== Controller = %x\n", Controller
));
837 Status
= gBS
->OpenProtocol (
839 &gEdkiiUfsHostControllerProtocolGuid
,
841 This
->DriverBindingHandle
,
843 EFI_OPEN_PROTOCOL_BY_DRIVER
846 if (EFI_ERROR (Status
)) {
847 DEBUG ((DEBUG_ERROR
, "Open Ufs Host Controller Protocol Error, Status = %r\n", Status
));
852 // Get the UFS Host Controller MMIO Bar Base Address.
854 Status
= UfsHc
->GetUfsHcMmioBar (UfsHc
, &UfsHcBase
);
855 if (EFI_ERROR (Status
)) {
856 DEBUG ((DEBUG_ERROR
, "Get Ufs Host Controller Mmio Bar Error, Status = %r\n", Status
));
861 // Initialize Ufs Pass Thru private data for managed UFS Host Controller.
863 Private
= AllocateCopyPool (sizeof (UFS_PASS_THRU_PRIVATE_DATA
), &gUfsPassThruTemplate
);
864 if (Private
== NULL
) {
865 DEBUG ((DEBUG_ERROR
, "Unable to allocate Ufs Pass Thru private data\n"));
866 Status
= EFI_OUT_OF_RESOURCES
;
870 Private
->ExtScsiPassThru
.Mode
= &Private
->ExtScsiPassThruMode
;
871 Private
->UfsHostController
= UfsHc
;
872 Private
->UfsHcBase
= UfsHcBase
;
873 InitializeListHead (&Private
->Queue
);
876 // Initialize UFS Host Controller H/W.
878 Status
= UfsControllerInit (Private
);
879 if (EFI_ERROR (Status
)) {
880 DEBUG ((DEBUG_ERROR
, "Ufs Host Controller Initialization Error, Status = %r\n", Status
));
885 // UFS 2.0 spec Section 13.1.3.3:
886 // At the end of the UFS Interconnect Layer initialization on both host and device side,
887 // the host shall send a NOP OUT UPIU to verify that the device UTP Layer is ready.
889 Status
= UfsExecNopCmds (Private
);
890 if (EFI_ERROR (Status
)) {
891 DEBUG ((DEBUG_ERROR
, "Ufs Sending NOP IN command Error, Status = %r\n", Status
));
895 Status
= UfsFinishDeviceInitialization (Private
);
896 if (EFI_ERROR (Status
)) {
897 DEBUG ((DEBUG_ERROR
, "Device failed to finish initialization, Status = %r\n", Status
));
902 // Check if 8 common luns are active and set corresponding bit mask.
903 // TODO: Parse device descriptor to decide if exposing RPMB LUN to upper layer for authentication access.
905 UnitDescriptorSize
= sizeof (UFS_UNIT_DESC
);
906 for (Index
= 0; Index
< 8; Index
++) {
907 Status
= UfsRwDeviceDesc (Private
, TRUE
, UfsUnitDesc
, (UINT8
) Index
, 0, &UnitDescriptor
, &UnitDescriptorSize
);
908 if (EFI_ERROR (Status
)) {
909 DEBUG ((DEBUG_ERROR
, "Failed to read unit descriptor, index = %X, status = %r\n", Index
, Status
));
912 if (UnitDescriptor
.LunEn
== 0x1) {
913 DEBUG ((DEBUG_INFO
, "UFS LUN %X is enabled\n", Index
));
914 Private
->Luns
.BitMask
|= (BIT0
<< Index
);
919 // Start the asynchronous interrupt monitor
921 Status
= gBS
->CreateEvent (
922 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
924 ProcessAsyncTaskList
,
928 if (EFI_ERROR (Status
)) {
929 DEBUG ((DEBUG_ERROR
, "Ufs Create Async Tasks Event Error, Status = %r\n", Status
));
933 Status
= gBS
->SetTimer (
938 if (EFI_ERROR (Status
)) {
939 DEBUG ((DEBUG_ERROR
, "Ufs Set Periodic Timer Error, Status = %r\n", Status
));
943 Status
= gBS
->InstallMultipleProtocolInterfaces (
945 &gEfiExtScsiPassThruProtocolGuid
,
946 &(Private
->ExtScsiPassThru
),
947 &gEfiUfsDeviceConfigProtocolGuid
,
948 &(Private
->UfsDevConfig
),
951 ASSERT_EFI_ERROR (Status
);
956 if (Private
!= NULL
) {
957 if (Private
->TmrlMapping
!= NULL
) {
958 UfsHc
->Unmap (UfsHc
, Private
->TmrlMapping
);
960 if (Private
->UtpTmrlBase
!= NULL
) {
961 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (Private
->Nutmrs
* sizeof (UTP_TMRD
)), Private
->UtpTmrlBase
);
964 if (Private
->TrlMapping
!= NULL
) {
965 UfsHc
->Unmap (UfsHc
, Private
->TrlMapping
);
967 if (Private
->UtpTrlBase
!= NULL
) {
968 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (Private
->Nutrs
* sizeof (UTP_TMRD
)), Private
->UtpTrlBase
);
971 if (Private
->TimerEvent
!= NULL
) {
972 gBS
->CloseEvent (Private
->TimerEvent
);
981 &gEdkiiUfsHostControllerProtocolGuid
,
982 This
->DriverBindingHandle
,
991 Stops a device controller or a bus controller.
993 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
994 As a result, much of the error checking on the parameters to Stop() has been moved
995 into this common boot service. It is legal to call Stop() from other locations,
996 but the following calling restrictions must be followed or the system behavior will not be deterministic.
997 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
998 same driver's Start() function.
999 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
1000 EFI_HANDLE. In addition, all of these handles must have been created in this driver's
1001 Start() function, and the Start() function must have called OpenProtocol() on
1002 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
1004 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1005 @param[in] ControllerHandle A handle to the device being stopped. The handle must
1006 support a bus specific I/O protocol for the driver
1007 to use to stop the device.
1008 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
1009 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
1010 if NumberOfChildren is 0.
1012 @retval EFI_SUCCESS The device was stopped.
1013 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
1018 UfsPassThruDriverBindingStop (
1019 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1020 IN EFI_HANDLE Controller
,
1021 IN UINTN NumberOfChildren
,
1022 IN EFI_HANDLE
*ChildHandleBuffer
1026 UFS_PASS_THRU_PRIVATE_DATA
*Private
;
1027 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
1028 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1029 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
1031 LIST_ENTRY
*NextEntry
;
1033 DEBUG ((DEBUG_INFO
, "==UfsPassThru Stop== Controller Controller = %x\n", Controller
));
1035 Status
= gBS
->OpenProtocol (
1037 &gEfiExtScsiPassThruProtocolGuid
,
1038 (VOID
**) &ExtScsiPassThru
,
1039 This
->DriverBindingHandle
,
1041 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1044 if (EFI_ERROR (Status
)) {
1045 return EFI_DEVICE_ERROR
;
1048 Private
= UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS (ExtScsiPassThru
);
1049 UfsHc
= Private
->UfsHostController
;
1052 // Cleanup the resources of I/O requests in the async I/O queue
1054 if (!IsListEmpty(&Private
->Queue
)) {
1055 EFI_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->Queue
) {
1056 TransReq
= UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry
);
1059 // TODO: Should find/add a proper host adapter return status for this
1062 TransReq
->Packet
->HostAdapterStatus
=
1063 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
;
1065 SignalCallerEvent (Private
, TransReq
);
1069 Status
= gBS
->UninstallMultipleProtocolInterfaces (
1071 &gEfiExtScsiPassThruProtocolGuid
,
1072 &(Private
->ExtScsiPassThru
),
1073 &gEfiUfsDeviceConfigProtocolGuid
,
1074 &(Private
->UfsDevConfig
),
1078 if (EFI_ERROR (Status
)) {
1079 return EFI_DEVICE_ERROR
;
1083 // Stop Ufs Host Controller
1085 Status
= UfsControllerStop (Private
);
1086 ASSERT_EFI_ERROR (Status
);
1088 if (Private
->TmrlMapping
!= NULL
) {
1089 UfsHc
->Unmap (UfsHc
, Private
->TmrlMapping
);
1091 if (Private
->UtpTmrlBase
!= NULL
) {
1092 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (Private
->Nutmrs
* sizeof (UTP_TMRD
)), Private
->UtpTmrlBase
);
1095 if (Private
->TrlMapping
!= NULL
) {
1096 UfsHc
->Unmap (UfsHc
, Private
->TrlMapping
);
1098 if (Private
->UtpTrlBase
!= NULL
) {
1099 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (Private
->Nutrs
* sizeof (UTP_TMRD
)), Private
->UtpTrlBase
);
1102 if (Private
->TimerEvent
!= NULL
) {
1103 gBS
->CloseEvent (Private
->TimerEvent
);
1109 // Close protocols opened by UfsPassThru controller driver
1111 gBS
->CloseProtocol (
1113 &gEdkiiUfsHostControllerProtocolGuid
,
1114 This
->DriverBindingHandle
,
1123 The user Entry Point for module UfsPassThru. The user code starts with this function.
1125 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1126 @param[in] SystemTable A pointer to the EFI System Table.
1128 @retval EFI_SUCCESS The entry point is executed successfully.
1129 @retval other Some error occurs when executing this entry point.
1134 InitializeUfsPassThru (
1135 IN EFI_HANDLE ImageHandle
,
1136 IN EFI_SYSTEM_TABLE
*SystemTable
1142 // Install driver model protocol(s).
1144 Status
= EfiLibInstallDriverBindingComponentName2 (
1147 &gUfsPassThruDriverBinding
,
1149 &gUfsPassThruComponentName
,
1150 &gUfsPassThruComponentName2
1152 ASSERT_EFI_ERROR (Status
);