]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c
MdeModulePkg/UfsPassThruDxe: Refactor private data to use UfsHcInfo
[mirror_edk2.git] / MdeModulePkg / Bus / Ufs / UfsPassThruDxe / UfsPassThruHci.c
1 /** @file
2 UfsPassThruDxe driver is used to produce EFI_EXT_SCSI_PASS_THRU protocol interface
3 for upper layer application to execute UFS-supported SCSI cmds.
4
5 Copyright (c) 2014 - 2019, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "UfsPassThru.h"
11
12 /**
13 Read 32bits data from specified UFS MMIO register.
14
15 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
16 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
17 the memory operation.
18 @param[out] Value The data buffer to store.
19
20 @retval EFI_TIMEOUT The operation is time out.
21 @retval EFI_SUCCESS The operation succeeds.
22 @retval Others The operation fails.
23
24 **/
25 EFI_STATUS
26 UfsMmioRead32 (
27 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
28 IN UINTN Offset,
29 OUT UINT32 *Value
30 )
31 {
32 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
33 EFI_STATUS Status;
34
35 UfsHc = Private->UfsHostController;
36
37 Status = UfsHc->Read (UfsHc, EfiUfsHcWidthUint32, Offset, 1, Value);
38
39 return Status;
40 }
41
42 /**
43 Write 32bits data to specified UFS MMIO register.
44
45 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
46 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
47 the memory operation.
48 @param[in] Value The data to write.
49
50 @retval EFI_TIMEOUT The operation is time out.
51 @retval EFI_SUCCESS The operation succeeds.
52 @retval Others The operation fails.
53
54 **/
55 EFI_STATUS
56 UfsMmioWrite32 (
57 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
58 IN UINTN Offset,
59 IN UINT32 Value
60 )
61 {
62 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
63 EFI_STATUS Status;
64
65 UfsHc = Private->UfsHostController;
66
67 Status = UfsHc->Write (UfsHc, EfiUfsHcWidthUint32, Offset, 1, &Value);
68
69 return Status;
70 }
71
72 /**
73 Wait for the value of the specified system memory set to the test value.
74
75 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
76 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
77 the memory operation.
78 @param[in] MaskValue The mask value of memory.
79 @param[in] TestValue The test value of memory.
80 @param[in] Timeout The time out value for wait memory set, uses 100ns as a unit.
81
82 @retval EFI_TIMEOUT The system memory setting is time out.
83 @retval EFI_SUCCESS The system memory is correct set.
84 @retval Others The operation fails.
85
86 **/
87 EFI_STATUS
88 UfsWaitMemSet (
89 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
90 IN UINTN Offset,
91 IN UINT32 MaskValue,
92 IN UINT32 TestValue,
93 IN UINT64 Timeout
94 )
95 {
96 UINT32 Value;
97 UINT64 Delay;
98 BOOLEAN InfiniteWait;
99 EFI_STATUS Status;
100
101 if (Timeout == 0) {
102 InfiniteWait = TRUE;
103 } else {
104 InfiniteWait = FALSE;
105 }
106
107 Delay = DivU64x32 (Timeout, 10) + 1;
108
109 do {
110 //
111 // Access PCI MMIO space to see if the value is the tested one.
112 //
113 Status = UfsMmioRead32 (Private, Offset, &Value);
114 if (EFI_ERROR (Status)) {
115 return Status;
116 }
117
118 Value &= MaskValue;
119
120 if (Value == TestValue) {
121 return EFI_SUCCESS;
122 }
123
124 //
125 // Stall for 1 microseconds.
126 //
127 MicroSecondDelay (1);
128
129 Delay--;
130
131 } while (InfiniteWait || (Delay > 0));
132
133 return EFI_TIMEOUT;
134 }
135
136 /**
137 Dump UIC command execution result for debugging.
138
139 @param[in] UicOpcode The executed UIC opcode.
140 @param[in] Result The result to be parsed.
141
142 **/
143 VOID
144 DumpUicCmdExecResult (
145 IN UINT8 UicOpcode,
146 IN UINT8 Result
147 )
148 {
149 if (UicOpcode <= UfsUicDmePeerSet) {
150 switch (Result) {
151 case 0x00:
152 break;
153 case 0x01:
154 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));
155 break;
156 case 0x02:
157 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));
158 break;
159 case 0x03:
160 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));
161 break;
162 case 0x04:
163 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));
164 break;
165 case 0x05:
166 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BAD_INDEX\n"));
167 break;
168 case 0x06:
169 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));
170 break;
171 case 0x07:
172 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));
173 break;
174 case 0x08:
175 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));
176 break;
177 case 0x09:
178 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BUSY\n"));
179 break;
180 case 0x0A:
181 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - DME_FAILURE\n"));
182 break;
183 default :
184 ASSERT (FALSE);
185 break;
186 }
187 } else {
188 switch (Result) {
189 case 0x00:
190 break;
191 case 0x01:
192 DEBUG ((DEBUG_VERBOSE, "UIC control command fails - FAILURE\n"));
193 break;
194 default :
195 ASSERT (FALSE);
196 break;
197 }
198 }
199 }
200
201 /**
202 Dump QUERY RESPONSE UPIU result for debugging.
203
204 @param[in] Result The result to be parsed.
205
206 **/
207 VOID
208 DumpQueryResponseResult (
209 IN UINT8 Result
210 )
211 {
212 switch (Result) {
213 case 0xF6:
214 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Not Readable\n"));
215 break;
216 case 0xF7:
217 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Not Writeable\n"));
218 break;
219 case 0xF8:
220 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Already Written\n"));
221 break;
222 case 0xF9:
223 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Length\n"));
224 break;
225 case 0xFA:
226 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Value\n"));
227 break;
228 case 0xFB:
229 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Selector\n"));
230 break;
231 case 0xFC:
232 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Index\n"));
233 break;
234 case 0xFD:
235 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Idn\n"));
236 break;
237 case 0xFE:
238 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Opcode\n"));
239 break;
240 case 0xFF:
241 DEBUG ((DEBUG_VERBOSE, "Query Response with General Failure\n"));
242 break;
243 default :
244 ASSERT (FALSE);
245 break;
246 }
247 }
248
249 /**
250 Swap little endian to big endian.
251
252 @param[in, out] Buffer The data buffer. In input, it contains little endian data.
253 In output, it will become big endian.
254 @param[in] BufferSize The length of converted data.
255
256 **/
257 VOID
258 SwapLittleEndianToBigEndian (
259 IN OUT UINT8 *Buffer,
260 IN UINT32 BufferSize
261 )
262 {
263 UINT32 Index;
264 UINT8 Temp;
265 UINT32 SwapCount;
266
267 SwapCount = BufferSize / 2;
268 for (Index = 0; Index < SwapCount; Index++) {
269 Temp = Buffer[Index];
270 Buffer[Index] = Buffer[BufferSize - 1 - Index];
271 Buffer[BufferSize - 1 - Index] = Temp;
272 }
273 }
274
275 /**
276 Fill TSF field of QUERY REQUEST UPIU.
277
278 @param[in, out] TsfBase The base address of TSF field of QUERY REQUEST UPIU.
279 @param[in] Opcode The opcode of request.
280 @param[in] DescId The descriptor ID of request.
281 @param[in] Index The index of request.
282 @param[in] Selector The selector of request.
283 @param[in] Length The length of transferred data. The maximum is 4.
284 @param[in] Value The value of transferred data.
285
286 **/
287 VOID
288 UfsFillTsfOfQueryReqUpiu (
289 IN OUT UTP_UPIU_TSF *TsfBase,
290 IN UINT8 Opcode,
291 IN UINT8 DescId OPTIONAL,
292 IN UINT8 Index OPTIONAL,
293 IN UINT8 Selector OPTIONAL,
294 IN UINT16 Length OPTIONAL,
295 IN UINT32 Value OPTIONAL
296 )
297 {
298 ASSERT (TsfBase != NULL);
299 ASSERT (Opcode <= UtpQueryFuncOpcodeTogFlag);
300
301 TsfBase->Opcode = Opcode;
302 if (Opcode != UtpQueryFuncOpcodeNop) {
303 TsfBase->DescId = DescId;
304 TsfBase->Index = Index;
305 TsfBase->Selector = Selector;
306
307 if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {
308 SwapLittleEndianToBigEndian ((UINT8*)&Length, sizeof (Length));
309 TsfBase->Length = Length;
310 }
311
312 if (Opcode == UtpQueryFuncOpcodeWrAttr) {
313 SwapLittleEndianToBigEndian ((UINT8*)&Value, sizeof (Value));
314 TsfBase->Value = Value;
315 }
316 }
317 }
318
319 /**
320 Initialize COMMAND UPIU.
321
322 @param[in, out] Command The base address of COMMAND UPIU.
323 @param[in] Lun The Lun on which the SCSI command is executed.
324 @param[in] TaskTag The task tag of request.
325 @param[in] Cdb The cdb buffer containing SCSI command.
326 @param[in] CdbLength The cdb length.
327 @param[in] DataDirection The direction of data transfer.
328 @param[in] ExpDataTranLen The expected transfer data length.
329
330 @retval EFI_SUCCESS The initialization succeed.
331
332 **/
333 EFI_STATUS
334 UfsInitCommandUpiu (
335 IN OUT UTP_COMMAND_UPIU *Command,
336 IN UINT8 Lun,
337 IN UINT8 TaskTag,
338 IN UINT8 *Cdb,
339 IN UINT8 CdbLength,
340 IN UFS_DATA_DIRECTION DataDirection,
341 IN UINT32 ExpDataTranLen
342 )
343 {
344 UINT8 Flags;
345
346 ASSERT ((Command != NULL) && (Cdb != NULL));
347
348 //
349 // Task attribute is hard-coded to Ordered.
350 //
351 if (DataDirection == UfsDataIn) {
352 Flags = BIT0 | BIT6;
353 } else if (DataDirection == UfsDataOut) {
354 Flags = BIT0 | BIT5;
355 } else {
356 Flags = BIT0;
357 }
358
359 //
360 // Fill UTP COMMAND UPIU associated fields.
361 //
362 Command->TransCode = 0x01;
363 Command->Flags = Flags;
364 Command->Lun = Lun;
365 Command->TaskTag = TaskTag;
366 Command->CmdSet = 0x00;
367 SwapLittleEndianToBigEndian ((UINT8*)&ExpDataTranLen, sizeof (ExpDataTranLen));
368 Command->ExpDataTranLen = ExpDataTranLen;
369
370 CopyMem (Command->Cdb, Cdb, CdbLength);
371
372 return EFI_SUCCESS;
373 }
374
375 /**
376 Initialize UTP PRDT for data transfer.
377
378 @param[in] Prdt The base address of PRDT.
379 @param[in] Buffer The buffer to be read or written.
380 @param[in] BufferSize The data size to be read or written.
381
382 @retval EFI_SUCCESS The initialization succeed.
383
384 **/
385 EFI_STATUS
386 UfsInitUtpPrdt (
387 IN UTP_TR_PRD *Prdt,
388 IN VOID *Buffer,
389 IN UINT32 BufferSize
390 )
391 {
392 UINT32 PrdtIndex;
393 UINT32 RemainingLen;
394 UINT8 *Remaining;
395 UINTN PrdtNumber;
396
397 ASSERT (((UINTN)Buffer & (BIT0 | BIT1)) == 0);
398 ASSERT ((BufferSize & (BIT1 | BIT0)) == 0);
399
400 if (BufferSize == 0) {
401 return EFI_SUCCESS;
402 }
403
404 RemainingLen = BufferSize;
405 Remaining = Buffer;
406 PrdtNumber = (UINTN)DivU64x32 ((UINT64)BufferSize + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);
407
408 for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {
409 if (RemainingLen < UFS_MAX_DATA_LEN_PER_PRD) {
410 Prdt[PrdtIndex].DbCount = (UINT32)RemainingLen - 1;
411 } else {
412 Prdt[PrdtIndex].DbCount = UFS_MAX_DATA_LEN_PER_PRD - 1;
413 }
414
415 Prdt[PrdtIndex].DbAddr = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 2);
416 Prdt[PrdtIndex].DbAddrU = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 32);
417 RemainingLen -= UFS_MAX_DATA_LEN_PER_PRD;
418 Remaining += UFS_MAX_DATA_LEN_PER_PRD;
419 }
420
421 return EFI_SUCCESS;
422 }
423
424 /**
425 Initialize QUERY REQUEST UPIU.
426
427 @param[in, out] QueryReq The base address of QUERY REQUEST UPIU.
428 @param[in] TaskTag The task tag of request.
429 @param[in] Opcode The opcode of request.
430 @param[in] DescId The descriptor ID of request.
431 @param[in] Index The index of request.
432 @param[in] Selector The selector of request.
433 @param[in] DataSize The data size to be read or written.
434 @param[in] Data The buffer to be read or written.
435
436 @retval EFI_SUCCESS The initialization succeed.
437
438 **/
439 EFI_STATUS
440 UfsInitQueryRequestUpiu (
441 IN OUT UTP_QUERY_REQ_UPIU *QueryReq,
442 IN UINT8 TaskTag,
443 IN UINT8 Opcode,
444 IN UINT8 DescId,
445 IN UINT8 Index,
446 IN UINT8 Selector,
447 IN UINTN DataSize OPTIONAL,
448 IN UINT8 *Data OPTIONAL
449 )
450 {
451 ASSERT (QueryReq != NULL);
452
453 QueryReq->TransCode = 0x16;
454 QueryReq->TaskTag = TaskTag;
455 if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeRdFlag) || (Opcode == UtpQueryFuncOpcodeRdAttr)) {
456 QueryReq->QueryFunc = QUERY_FUNC_STD_READ_REQ;
457 } else {
458 QueryReq->QueryFunc = QUERY_FUNC_STD_WRITE_REQ;
459 }
460
461 if (Opcode == UtpQueryFuncOpcodeWrAttr) {
462 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, *(UINT32*)Data);
463 } else if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {
464 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, (UINT16)DataSize, 0);
465 } else {
466 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, 0);
467 }
468
469 if (Opcode == UtpQueryFuncOpcodeWrDesc) {
470 CopyMem (QueryReq + 1, Data, DataSize);
471
472 SwapLittleEndianToBigEndian ((UINT8*)&DataSize, sizeof (UINT16));
473 QueryReq->DataSegLen = (UINT16)DataSize;
474 }
475
476 return EFI_SUCCESS;
477 }
478
479 /**
480 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
481
482 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
483 @param[in] Lun The Lun on which the SCSI command is executed.
484 @param[in] Packet The pointer to the EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.
485 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
486 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
487 @param[out] CmdDescMapping A resulting value to pass to Unmap().
488
489 @retval EFI_SUCCESS The creation succeed.
490 @retval EFI_DEVICE_ERROR The creation failed.
491 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
492
493 **/
494 EFI_STATUS
495 UfsCreateScsiCommandDesc (
496 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
497 IN UINT8 Lun,
498 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
499 IN UTP_TRD *Trd,
500 OUT VOID **CmdDescHost,
501 OUT VOID **CmdDescMapping
502 )
503 {
504 UINTN TotalLen;
505 UINTN PrdtNumber;
506 UTP_COMMAND_UPIU *CommandUpiu;
507 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
508 EFI_STATUS Status;
509 UINT32 DataLen;
510 UFS_DATA_DIRECTION DataDirection;
511
512 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
513
514 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
515 DataLen = Packet->InTransferLength;
516 DataDirection = UfsDataIn;
517 } else {
518 DataLen = Packet->OutTransferLength;
519 DataDirection = UfsDataOut;
520 }
521
522 if (DataLen == 0) {
523 DataDirection = UfsNoData;
524 }
525
526 PrdtNumber = (UINTN)DivU64x32 ((UINT64)DataLen + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);
527
528 TotalLen = ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)) + PrdtNumber * sizeof (UTP_TR_PRD);
529
530 Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);
531 if (EFI_ERROR (Status)) {
532 return Status;
533 }
534
535 CommandUpiu = (UTP_COMMAND_UPIU*)*CmdDescHost;
536
537 UfsInitCommandUpiu (CommandUpiu, Lun, Private->TaskTag++, Packet->Cdb, Packet->CdbLength, DataDirection, DataLen);
538
539 //
540 // Fill UTP_TRD associated fields
541 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
542 // *MUST* be located at a 64-bit aligned boundary.
543 //
544 Trd->Int = UFS_INTERRUPT_COMMAND;
545 Trd->Dd = DataDirection;
546 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
547 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
548 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);
549 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);
550 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)), sizeof (UINT32));
551 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)), sizeof (UINT32));
552 Trd->PrdtL = (UINT16)PrdtNumber;
553 Trd->PrdtO = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))), sizeof (UINT32));
554 return EFI_SUCCESS;
555 }
556
557 /**
558 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
559
560 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
561 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
562 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
563 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
564 @param[out] CmdDescMapping A resulting value to pass to Unmap().
565
566 @retval EFI_SUCCESS The creation succeed.
567 @retval EFI_DEVICE_ERROR The creation failed.
568 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
569 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
570
571 **/
572 EFI_STATUS
573 UfsCreateDMCommandDesc (
574 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
575 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,
576 IN UTP_TRD *Trd,
577 OUT VOID **CmdDescHost,
578 OUT VOID **CmdDescMapping
579 )
580 {
581 UINTN TotalLen;
582 UTP_QUERY_REQ_UPIU *QueryReqUpiu;
583 UINT8 Opcode;
584 UINT32 DataSize;
585 UINT8 *Data;
586 UINT8 DataDirection;
587 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
588 EFI_STATUS Status;
589
590 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
591
592 Opcode = Packet->Opcode;
593 if ((Opcode > UtpQueryFuncOpcodeTogFlag) || (Opcode == UtpQueryFuncOpcodeNop)) {
594 return EFI_INVALID_PARAMETER;
595 }
596
597 DataDirection = Packet->DataDirection;
598 DataSize = Packet->TransferLength;
599 Data = Packet->DataBuffer;
600
601 if ((Opcode == UtpQueryFuncOpcodeWrDesc) || (Opcode == UtpQueryFuncOpcodeRdDesc)) {
602 if (DataSize == 0 || Data == NULL) {
603 return EFI_INVALID_PARAMETER;
604 }
605 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize);
606 } else {
607 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU));
608 }
609
610 Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);
611 if (EFI_ERROR (Status)) {
612 return Status;
613 }
614
615 //
616 // Initialize UTP QUERY REQUEST UPIU
617 //
618 QueryReqUpiu = (UTP_QUERY_REQ_UPIU*)*CmdDescHost;
619 ASSERT (QueryReqUpiu != NULL);
620 UfsInitQueryRequestUpiu (
621 QueryReqUpiu,
622 Private->TaskTag++,
623 Opcode,
624 Packet->DescId,
625 Packet->Index,
626 Packet->Selector,
627 DataSize,
628 Data
629 );
630
631 //
632 // Fill UTP_TRD associated fields
633 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
634 //
635 Trd->Int = UFS_INTERRUPT_COMMAND;
636 Trd->Dd = DataDirection;
637 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
638 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
639 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);
640 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);
641 if (Opcode == UtpQueryFuncOpcodeWrDesc) {
642 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)), sizeof (UINT32));
643 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));
644 } else {
645 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));
646 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)), sizeof (UINT32));
647 }
648
649 return EFI_SUCCESS;
650 }
651
652 /**
653 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
654
655 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
656 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
657 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
658 @param[out] CmdDescMapping A resulting value to pass to Unmap().
659
660 @retval EFI_SUCCESS The creation succeed.
661 @retval EFI_DEVICE_ERROR The creation failed.
662 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
663
664 **/
665 EFI_STATUS
666 UfsCreateNopCommandDesc (
667 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
668 IN UTP_TRD *Trd,
669 OUT VOID **CmdDescHost,
670 OUT VOID **CmdDescMapping
671 )
672 {
673 UINTN TotalLen;
674 UTP_NOP_OUT_UPIU *NopOutUpiu;
675 EFI_STATUS Status;
676 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
677
678 ASSERT ((Private != NULL) && (Trd != NULL));
679
680 TotalLen = ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU));
681 Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);
682 if (EFI_ERROR (Status)) {
683 return Status;
684 }
685
686 NopOutUpiu = (UTP_NOP_OUT_UPIU*)*CmdDescHost;
687 ASSERT (NopOutUpiu != NULL);
688 NopOutUpiu->TaskTag = Private->TaskTag++;
689
690 //
691 // Fill UTP_TRD associated fields
692 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
693 //
694 Trd->Int = UFS_INTERRUPT_COMMAND;
695 Trd->Dd = 0x00;
696 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
697 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
698 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);
699 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);
700 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU)), sizeof (UINT32));
701 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)), sizeof (UINT32));
702
703 return EFI_SUCCESS;
704 }
705
706 /**
707 Find out available slot in transfer list of a UFS device.
708
709 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
710 @param[out] Slot The available slot.
711
712 @retval EFI_SUCCESS The available slot was found successfully.
713 @retval EFI_NOT_READY No slot is available at this moment.
714
715 **/
716 EFI_STATUS
717 UfsFindAvailableSlotInTrl (
718 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
719 OUT UINT8 *Slot
720 )
721 {
722 UINT8 Nutrs;
723 UINT8 Index;
724 UINT32 Data;
725 EFI_STATUS Status;
726
727 ASSERT ((Private != NULL) && (Slot != NULL));
728
729 Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Data);
730 if (EFI_ERROR (Status)) {
731 return Status;
732 }
733
734 Nutrs = (UINT8)((Private->UfsHcInfo.Capabilities & UFS_HC_CAP_NUTRS) + 1);
735
736 for (Index = 0; Index < Nutrs; Index++) {
737 if ((Data & (BIT0 << Index)) == 0) {
738 *Slot = Index;
739 return EFI_SUCCESS;
740 }
741 }
742
743 return EFI_NOT_READY;
744 }
745
746
747 /**
748 Start specified slot in transfer list of a UFS device.
749
750 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
751 @param[in] Slot The slot to be started.
752
753 **/
754 EFI_STATUS
755 UfsStartExecCmd (
756 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
757 IN UINT8 Slot
758 )
759 {
760 UINT32 Data;
761 EFI_STATUS Status;
762
763 Status = UfsMmioRead32 (Private, UFS_HC_UTRLRSR_OFFSET, &Data);
764 if (EFI_ERROR (Status)) {
765 return Status;
766 }
767
768 if ((Data & UFS_HC_UTRLRSR) != UFS_HC_UTRLRSR) {
769 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, UFS_HC_UTRLRSR);
770 if (EFI_ERROR (Status)) {
771 return Status;
772 }
773 }
774
775 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << Slot);
776 if (EFI_ERROR (Status)) {
777 return Status;
778 }
779
780 return EFI_SUCCESS;
781 }
782
783 /**
784 Stop specified slot in transfer list of a UFS device.
785
786 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
787 @param[in] Slot The slot to be stop.
788
789 **/
790 EFI_STATUS
791 UfsStopExecCmd (
792 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
793 IN UINT8 Slot
794 )
795 {
796 UINT32 Data;
797 EFI_STATUS Status;
798
799 Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Data);
800 if (EFI_ERROR (Status)) {
801 return Status;
802 }
803
804 if ((Data & (BIT0 << Slot)) != 0) {
805 Status = UfsMmioRead32 (Private, UFS_HC_UTRLCLR_OFFSET, &Data);
806 if (EFI_ERROR (Status)) {
807 return Status;
808 }
809
810 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLCLR_OFFSET, Data & ~(BIT0 << Slot));
811 if (EFI_ERROR (Status)) {
812 return Status;
813 }
814 }
815
816 return EFI_SUCCESS;
817 }
818
819 /**
820 Extracts return data from query response upiu.
821
822 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
823 @param[in] QueryResp Pointer to the query response.
824
825 @retval EFI_INVALID_PARAMETER Packet or QueryResp are empty or opcode is invalid.
826 @retval EFI_DEVICE_ERROR Data returned from device is invalid.
827 @retval EFI_SUCCESS Data extracted.
828
829 **/
830 EFI_STATUS
831 UfsGetReturnDataFromQueryResponse (
832 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,
833 IN UTP_QUERY_RESP_UPIU *QueryResp
834 )
835 {
836 UINT16 ReturnDataSize;
837 UINT32 ReturnData;
838
839 if (Packet == NULL || QueryResp == NULL) {
840 return EFI_INVALID_PARAMETER;
841 }
842
843 switch (Packet->Opcode) {
844 case UtpQueryFuncOpcodeRdDesc:
845 ReturnDataSize = QueryResp->Tsf.Length;
846 SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));
847 //
848 // Make sure the hardware device does not return more data than expected.
849 //
850 if (ReturnDataSize > Packet->TransferLength) {
851 return EFI_DEVICE_ERROR;
852 }
853
854 CopyMem (Packet->DataBuffer, (QueryResp + 1), ReturnDataSize);
855 Packet->TransferLength = ReturnDataSize;
856 break;
857 case UtpQueryFuncOpcodeWrDesc:
858 ReturnDataSize = QueryResp->Tsf.Length;
859 SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));
860 Packet->TransferLength = ReturnDataSize;
861 break;
862 case UtpQueryFuncOpcodeRdFlag:
863 case UtpQueryFuncOpcodeSetFlag:
864 case UtpQueryFuncOpcodeClrFlag:
865 case UtpQueryFuncOpcodeTogFlag:
866 CopyMem (Packet->DataBuffer, &QueryResp->Tsf.Value, sizeof (UINT8));
867 break;
868 case UtpQueryFuncOpcodeRdAttr:
869 case UtpQueryFuncOpcodeWrAttr:
870 ReturnData = QueryResp->Tsf.Value;
871 SwapLittleEndianToBigEndian ((UINT8*) &ReturnData, sizeof (UINT32));
872 CopyMem (Packet->DataBuffer, &ReturnData, sizeof (UINT32));
873 break;
874 default:
875 return EFI_INVALID_PARAMETER;
876 }
877
878 return EFI_SUCCESS;
879 }
880
881 /**
882 Creates Transfer Request descriptor and sends Query Request to the device.
883
884 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
885 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
886
887 @retval EFI_SUCCESS The device descriptor was read/written successfully.
888 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
889 combination to point to a type of UFS device descriptor.
890 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
891 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
892
893 **/
894 EFI_STATUS
895 UfsSendDmRequestRetry (
896 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
897 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet
898 )
899 {
900 UINT8 Slot;
901 UTP_TRD *Trd;
902 VOID *CmdDescHost;
903 VOID *CmdDescMapping;
904 UINT32 CmdDescSize;
905 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
906 UTP_QUERY_RESP_UPIU *QueryResp;
907 EFI_STATUS Status;
908
909 //
910 // Find out which slot of transfer request list is available.
911 //
912 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
913 if (EFI_ERROR (Status)) {
914 return Status;
915 }
916
917 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
918 //
919 // Fill transfer request descriptor to this slot.
920 //
921 Status = UfsCreateDMCommandDesc (Private, Packet, Trd, &CmdDescHost, &CmdDescMapping);
922 if (EFI_ERROR (Status)) {
923 DEBUG ((DEBUG_ERROR, "Failed to create DM command descriptor\n"));
924 return Status;
925 }
926
927 UfsHc = Private->UfsHostController;
928 QueryResp = (UTP_QUERY_RESP_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));
929 ASSERT (QueryResp != NULL);
930 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
931
932 //
933 // Start to execute the transfer request.
934 //
935 UfsStartExecCmd (Private, Slot);
936
937 //
938 // Wait for the completion of the transfer request.
939 //
940 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0, 0, Packet->Timeout);
941 if (EFI_ERROR (Status)) {
942 goto Exit;
943 }
944
945 if (Trd->Ocs != 0 || QueryResp->QueryResp != UfsUtpQueryResponseSuccess) {
946 DEBUG ((DEBUG_ERROR, "Failed to send query request, OCS = %X, QueryResp = %X\n", Trd->Ocs, QueryResp->QueryResp));
947 DumpQueryResponseResult (QueryResp->QueryResp);
948
949 if ((QueryResp->QueryResp == UfsUtpQueryResponseInvalidSelector) ||
950 (QueryResp->QueryResp == UfsUtpQueryResponseInvalidIndex) ||
951 (QueryResp->QueryResp == UfsUtpQueryResponseInvalidIdn)) {
952 Status = EFI_INVALID_PARAMETER;
953 } else {
954 Status = EFI_DEVICE_ERROR;
955 }
956 goto Exit;
957 }
958
959 Status = UfsGetReturnDataFromQueryResponse (Packet, QueryResp);
960 if (EFI_ERROR (Status)) {
961 DEBUG ((DEBUG_ERROR, "Failed to get return data from query response\n"));
962 goto Exit;
963 }
964
965 Exit:
966 UfsHc->Flush (UfsHc);
967
968 UfsStopExecCmd (Private, Slot);
969
970 if (CmdDescMapping != NULL) {
971 UfsHc->Unmap (UfsHc, CmdDescMapping);
972 }
973 if (CmdDescHost != NULL) {
974 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);
975 }
976
977 return Status;
978 }
979
980 /**
981 Sends Query Request to the device. Query is sent until device responds correctly or counter runs out.
982
983 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
984 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_PACKET.
985
986 @retval EFI_SUCCESS The device responded correctly to the Query request.
987 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
988 combination to point to a type of UFS device descriptor.
989 @retval EFI_DEVICE_ERROR A device error occurred while waiting for the response from the device.
990 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of the operation.
991
992 **/
993 EFI_STATUS
994 UfsSendDmRequest (
995 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
996 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet
997 )
998 {
999 EFI_STATUS Status;
1000 UINT8 Retry;
1001
1002 Status = EFI_SUCCESS;
1003
1004 for (Retry = 0; Retry < 5; Retry ++) {
1005 Status = UfsSendDmRequestRetry (Private, Packet);
1006 if (!EFI_ERROR (Status)) {
1007 return EFI_SUCCESS;
1008 }
1009 }
1010
1011 DEBUG ((DEBUG_ERROR, "Failed to get response from the device after %d retries\n", Retry));
1012 return Status;
1013 }
1014
1015 /**
1016 Read or write specified device descriptor of a UFS device.
1017
1018 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1019 @param[in] Read The boolean variable to show r/w direction.
1020 @param[in] DescId The ID of device descriptor.
1021 @param[in] Index The Index of device descriptor.
1022 @param[in] Selector The Selector of device descriptor.
1023 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
1024 @param[in, out] DescSize The size of device descriptor buffer. On input, the size, in bytes,
1025 of the data buffer specified by Descriptor. On output, the number
1026 of bytes that were actually transferred.
1027
1028 @retval EFI_SUCCESS The device descriptor was read/written successfully.
1029 @retval EFI_INVALID_PARAMETER DescId, Index and Selector are invalid combination to point to a
1030 type of UFS device descriptor.
1031 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
1032 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
1033
1034 **/
1035 EFI_STATUS
1036 UfsRwDeviceDesc (
1037 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1038 IN BOOLEAN Read,
1039 IN UINT8 DescId,
1040 IN UINT8 Index,
1041 IN UINT8 Selector,
1042 IN OUT VOID *Descriptor,
1043 IN OUT UINT32 *DescSize
1044 )
1045 {
1046 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
1047 EFI_STATUS Status;
1048
1049 if (DescSize == NULL) {
1050 return EFI_INVALID_PARAMETER;
1051 }
1052
1053 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
1054
1055 if (Read) {
1056 Packet.DataDirection = UfsDataIn;
1057 Packet.Opcode = UtpQueryFuncOpcodeRdDesc;
1058 } else {
1059 Packet.DataDirection = UfsDataOut;
1060 Packet.Opcode = UtpQueryFuncOpcodeWrDesc;
1061 }
1062 Packet.DataBuffer = Descriptor;
1063 Packet.TransferLength = *DescSize;
1064 Packet.DescId = DescId;
1065 Packet.Index = Index;
1066 Packet.Selector = Selector;
1067 Packet.Timeout = UFS_TIMEOUT;
1068
1069 Status = UfsSendDmRequest (Private, &Packet);
1070 if (EFI_ERROR (Status)) {
1071 *DescSize = 0;
1072 } else {
1073 *DescSize = Packet.TransferLength;
1074 }
1075
1076 return Status;
1077 }
1078
1079 /**
1080 Read or write specified attribute of a UFS device.
1081
1082 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1083 @param[in] Read The boolean variable to show r/w direction.
1084 @param[in] AttrId The ID of Attribute.
1085 @param[in] Index The Index of Attribute.
1086 @param[in] Selector The Selector of Attribute.
1087 @param[in, out] Attributes The value of Attribute to be read or written.
1088
1089 @retval EFI_SUCCESS The Attribute was read/written successfully.
1090 @retval EFI_INVALID_PARAMETER AttrId, Index and Selector are invalid combination to point to a
1091 type of UFS device descriptor.
1092 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
1093 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
1094
1095 **/
1096 EFI_STATUS
1097 UfsRwAttributes (
1098 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1099 IN BOOLEAN Read,
1100 IN UINT8 AttrId,
1101 IN UINT8 Index,
1102 IN UINT8 Selector,
1103 IN OUT UINT32 *Attributes
1104 )
1105 {
1106 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
1107
1108 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
1109
1110 if (Read) {
1111 Packet.DataDirection = UfsDataIn;
1112 Packet.Opcode = UtpQueryFuncOpcodeRdAttr;
1113 } else {
1114 Packet.DataDirection = UfsDataOut;
1115 Packet.Opcode = UtpQueryFuncOpcodeWrAttr;
1116 }
1117 Packet.DataBuffer = Attributes;
1118 Packet.DescId = AttrId;
1119 Packet.Index = Index;
1120 Packet.Selector = Selector;
1121 Packet.Timeout = UFS_TIMEOUT;
1122
1123 return UfsSendDmRequest (Private, &Packet);
1124 }
1125
1126 /**
1127 Read or write specified flag of a UFS device.
1128
1129 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1130 @param[in] Read The boolean variable to show r/w direction.
1131 @param[in] FlagId The ID of flag to be read or written.
1132 @param[in, out] Value The value to set or clear flag.
1133
1134 @retval EFI_SUCCESS The flag was read/written successfully.
1135 @retval EFI_INVALID_PARAMETER FlagId is an invalid UFS flag ID.
1136 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
1137 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
1138
1139 **/
1140 EFI_STATUS
1141 UfsRwFlags (
1142 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1143 IN BOOLEAN Read,
1144 IN UINT8 FlagId,
1145 IN OUT UINT8 *Value
1146 )
1147 {
1148 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
1149
1150 if (Value == NULL) {
1151 return EFI_INVALID_PARAMETER;
1152 }
1153
1154 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
1155
1156 if (Read) {
1157 ASSERT (Value != NULL);
1158 Packet.DataDirection = UfsDataIn;
1159 Packet.Opcode = UtpQueryFuncOpcodeRdFlag;
1160 } else {
1161 Packet.DataDirection = UfsDataOut;
1162 if (*Value == 1) {
1163 Packet.Opcode = UtpQueryFuncOpcodeSetFlag;
1164 } else if (*Value == 0) {
1165 Packet.Opcode = UtpQueryFuncOpcodeClrFlag;
1166 } else {
1167 return EFI_INVALID_PARAMETER;
1168 }
1169 }
1170 Packet.DataBuffer = Value;
1171 Packet.DescId = FlagId;
1172 Packet.Index = 0;
1173 Packet.Selector = 0;
1174 Packet.Timeout = UFS_TIMEOUT;
1175
1176 return UfsSendDmRequest (Private, &Packet);
1177 }
1178
1179 /**
1180 Set specified flag to 1 on a UFS device.
1181
1182 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1183 @param[in] FlagId The ID of flag to be set.
1184
1185 @retval EFI_SUCCESS The flag was set successfully.
1186 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1187 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1188
1189 **/
1190 EFI_STATUS
1191 UfsSetFlag (
1192 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1193 IN UINT8 FlagId
1194 )
1195 {
1196 EFI_STATUS Status;
1197 UINT8 Value;
1198
1199 Value = 1;
1200 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);
1201
1202 return Status;
1203 }
1204
1205
1206
1207 /**
1208 Read specified flag from a UFS device.
1209
1210 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1211 @param[in] FlagId The ID of flag to be read.
1212 @param[out] Value The flag's value.
1213
1214 @retval EFI_SUCCESS The flag was read successfully.
1215 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1216 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1217
1218 **/
1219 EFI_STATUS
1220 UfsReadFlag (
1221 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1222 IN UINT8 FlagId,
1223 OUT UINT8 *Value
1224 )
1225 {
1226 EFI_STATUS Status;
1227
1228 Status = UfsRwFlags (Private, TRUE, FlagId, Value);
1229
1230 return Status;
1231 }
1232
1233 /**
1234 Sends NOP IN cmd to a UFS device for initialization process request.
1235 For more details, please refer to UFS 2.0 spec Figure 13.3.
1236
1237 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1238
1239 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1240 received successfully.
1241 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1242 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1243 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1244
1245 **/
1246 EFI_STATUS
1247 UfsExecNopCmds (
1248 IN UFS_PASS_THRU_PRIVATE_DATA *Private
1249 )
1250 {
1251 EFI_STATUS Status;
1252 UINT8 Slot;
1253 UTP_TRD *Trd;
1254 UTP_NOP_IN_UPIU *NopInUpiu;
1255 UINT32 CmdDescSize;
1256 VOID *CmdDescHost;
1257 VOID *CmdDescMapping;
1258 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
1259
1260 //
1261 // Find out which slot of transfer request list is available.
1262 //
1263 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
1264 if (EFI_ERROR (Status)) {
1265 return Status;
1266 }
1267
1268 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
1269 Status = UfsCreateNopCommandDesc (Private, Trd, &CmdDescHost, &CmdDescMapping);
1270 if (EFI_ERROR (Status)) {
1271 return Status;
1272 }
1273
1274 //
1275 // Check the transfer request result.
1276 //
1277 UfsHc = Private->UfsHostController;
1278 NopInUpiu = (UTP_NOP_IN_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));
1279 ASSERT (NopInUpiu != NULL);
1280 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
1281
1282 //
1283 // Start to execute the transfer request.
1284 //
1285 UfsStartExecCmd (Private, Slot);
1286
1287 //
1288 // Wait for the completion of the transfer request.
1289 //
1290 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << Slot, 0, UFS_TIMEOUT);
1291 if (EFI_ERROR (Status)) {
1292 goto Exit;
1293 }
1294
1295 if (NopInUpiu->Resp != 0) {
1296 Status = EFI_DEVICE_ERROR;
1297 } else {
1298 Status = EFI_SUCCESS;
1299 }
1300
1301 Exit:
1302 UfsHc->Flush (UfsHc);
1303
1304 UfsStopExecCmd (Private, Slot);
1305
1306 if (CmdDescMapping != NULL) {
1307 UfsHc->Unmap (UfsHc, CmdDescMapping);
1308 }
1309 if (CmdDescHost != NULL) {
1310 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);
1311 }
1312
1313 return Status;
1314 }
1315
1316 /**
1317 Cleanup data buffers after data transfer. This function
1318 also takes care to copy all data to user memory pool for
1319 unaligned data transfers.
1320
1321 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA
1322 @param[in] TransReq Pointer to the transfer request
1323 **/
1324 VOID
1325 UfsReconcileDataTransferBuffer (
1326 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1327 IN UFS_PASS_THRU_TRANS_REQ *TransReq
1328 )
1329 {
1330 if (TransReq->DataBufMapping != NULL) {
1331 Private->UfsHostController->Unmap (
1332 Private->UfsHostController,
1333 TransReq->DataBufMapping
1334 );
1335 }
1336
1337 //
1338 // Check if unaligned transfer was performed. If it was and we read
1339 // data from device copy memory to user data buffers before cleanup.
1340 // The assumption is if auxiliary aligned data buffer is not NULL then
1341 // unaligned transfer has been performed.
1342 //
1343 if (TransReq->AlignedDataBuf != NULL) {
1344 if (TransReq->Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
1345 CopyMem (TransReq->Packet->InDataBuffer, TransReq->AlignedDataBuf, TransReq->Packet->InTransferLength);
1346 }
1347 //
1348 // Wipe out the transfer buffer in case it contains sensitive data.
1349 //
1350 ZeroMem (TransReq->AlignedDataBuf, TransReq->AlignedDataBufSize);
1351 FreeAlignedPages (TransReq->AlignedDataBuf, EFI_SIZE_TO_PAGES (TransReq->AlignedDataBufSize));
1352 TransReq->AlignedDataBuf = NULL;
1353 }
1354 }
1355
1356 /**
1357 Prepare data buffer for transfer.
1358
1359 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA
1360 @param[in, out] TransReq Pointer to the transfer request
1361
1362 @retval EFI_DEVICE_ERROR Failed to prepare buffer for transfer
1363 @retval EFI_SUCCESS Buffer ready for transfer
1364 **/
1365 EFI_STATUS
1366 UfsPrepareDataTransferBuffer (
1367 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1368 IN OUT UFS_PASS_THRU_TRANS_REQ *TransReq
1369 )
1370 {
1371 EFI_STATUS Status;
1372 VOID *DataBuf;
1373 UINT32 DataLen;
1374 UINTN MapLength;
1375 EFI_PHYSICAL_ADDRESS DataBufPhyAddr;
1376 EDKII_UFS_HOST_CONTROLLER_OPERATION Flag;
1377 UTP_TR_PRD *PrdtBase;
1378
1379 DataBufPhyAddr = 0;
1380 DataBuf = NULL;
1381
1382 //
1383 // For unaligned data transfers we allocate auxiliary DWORD aligned memory pool.
1384 // When command is finished auxiliary memory pool is copied into actual user memory.
1385 // This is requiered to assure data transfer safety(DWORD alignment required by UFS spec.)
1386 //
1387 if (TransReq->Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
1388 if (((UINTN)TransReq->Packet->InDataBuffer % 4 != 0) || (TransReq->Packet->InTransferLength % 4 != 0)) {
1389 DataLen = TransReq->Packet->InTransferLength + (4 - (TransReq->Packet->InTransferLength % 4));
1390 DataBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen), 4);
1391 if (DataBuf == NULL) {
1392 return EFI_DEVICE_ERROR;
1393 }
1394 ZeroMem (DataBuf, DataLen);
1395 TransReq->AlignedDataBuf = DataBuf;
1396 TransReq->AlignedDataBufSize = DataLen;
1397 } else {
1398 DataLen = TransReq->Packet->InTransferLength;
1399 DataBuf = TransReq->Packet->InDataBuffer;
1400 }
1401 Flag = EdkiiUfsHcOperationBusMasterWrite;
1402 } else {
1403 if (((UINTN)TransReq->Packet->OutDataBuffer % 4 != 0) || (TransReq->Packet->OutTransferLength % 4 != 0)) {
1404 DataLen = TransReq->Packet->OutTransferLength + (4 - (TransReq->Packet->OutTransferLength % 4));
1405 DataBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen), 4);
1406 if (DataBuf == NULL) {
1407 return EFI_DEVICE_ERROR;
1408 }
1409 CopyMem (DataBuf, TransReq->Packet->OutDataBuffer, TransReq->Packet->OutTransferLength);
1410 TransReq->AlignedDataBuf = DataBuf;
1411 TransReq->AlignedDataBufSize = DataLen;
1412 } else {
1413 DataLen = TransReq->Packet->OutTransferLength;
1414 DataBuf = TransReq->Packet->OutDataBuffer;
1415 }
1416 Flag = EdkiiUfsHcOperationBusMasterRead;
1417 }
1418
1419 if (DataLen != 0) {
1420 MapLength = DataLen;
1421 Status = Private->UfsHostController->Map (
1422 Private->UfsHostController,
1423 Flag,
1424 DataBuf,
1425 &MapLength,
1426 &DataBufPhyAddr,
1427 &TransReq->DataBufMapping
1428 );
1429
1430 if (EFI_ERROR (Status) || (DataLen != MapLength)) {
1431 if (TransReq->AlignedDataBuf != NULL) {
1432 //
1433 // Wipe out the transfer buffer in case it contains sensitive data.
1434 //
1435 ZeroMem (TransReq->AlignedDataBuf, TransReq->AlignedDataBufSize);
1436 FreeAlignedPages (TransReq->AlignedDataBuf, EFI_SIZE_TO_PAGES (TransReq->AlignedDataBufSize));
1437 TransReq->AlignedDataBuf = NULL;
1438 }
1439 return EFI_DEVICE_ERROR;
1440 }
1441 }
1442
1443 //
1444 // Fill PRDT table of Command UPIU for executed SCSI cmd.
1445 //
1446 PrdtBase = (UTP_TR_PRD*)((UINT8*)TransReq->CmdDescHost + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));
1447 ASSERT (PrdtBase != NULL);
1448 UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)DataBufPhyAddr, DataLen);
1449
1450 return EFI_SUCCESS;
1451 }
1452
1453 /**
1454 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1455
1456 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1457 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1458 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1459 UFS device.
1460 @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking
1461 I/O is performed. If Event is NULL, then blocking I/O is performed. If
1462 Event is not NULL and non blocking I/O is supported, then
1463 nonblocking I/O is performed, and Event will be signaled when the
1464 SCSI Request Packet completes.
1465
1466 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1467 commands, InTransferLength bytes were transferred from
1468 InDataBuffer. For write and bi-directional commands,
1469 OutTransferLength bytes were transferred by
1470 OutDataBuffer.
1471 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1472 Packet.
1473 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1474 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1475
1476 **/
1477 EFI_STATUS
1478 UfsExecScsiCmds (
1479 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1480 IN UINT8 Lun,
1481 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
1482 IN EFI_EVENT Event OPTIONAL
1483 )
1484 {
1485 EFI_STATUS Status;
1486 UTP_RESPONSE_UPIU *Response;
1487 UINT16 SenseDataLen;
1488 UINT32 ResTranCount;
1489 EFI_TPL OldTpl;
1490 UFS_PASS_THRU_TRANS_REQ *TransReq;
1491 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
1492
1493 TransReq = AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ));
1494 if (TransReq == NULL) {
1495 return EFI_OUT_OF_RESOURCES;
1496 }
1497
1498 TransReq->Signature = UFS_PASS_THRU_TRANS_REQ_SIG;
1499 TransReq->TimeoutRemain = Packet->Timeout;
1500 TransReq->Packet = Packet;
1501
1502 UfsHc = Private->UfsHostController;
1503 //
1504 // Find out which slot of transfer request list is available.
1505 //
1506 Status = UfsFindAvailableSlotInTrl (Private, &TransReq->Slot);
1507 if (EFI_ERROR (Status)) {
1508 return Status;
1509 }
1510
1511 TransReq->Trd = ((UTP_TRD*)Private->UtpTrlBase) + TransReq->Slot;
1512
1513 //
1514 // Fill transfer request descriptor to this slot.
1515 //
1516 Status = UfsCreateScsiCommandDesc (
1517 Private,
1518 Lun,
1519 Packet,
1520 TransReq->Trd,
1521 &TransReq->CmdDescHost,
1522 &TransReq->CmdDescMapping
1523 );
1524 if (EFI_ERROR (Status)) {
1525 return Status;
1526 }
1527
1528 TransReq->CmdDescSize = TransReq->Trd->PrdtO * sizeof (UINT32) + TransReq->Trd->PrdtL * sizeof (UTP_TR_PRD);
1529
1530 Status = UfsPrepareDataTransferBuffer (Private, TransReq);
1531 if (EFI_ERROR (Status)) {
1532 goto Exit1;
1533 }
1534
1535 //
1536 // Insert the async SCSI cmd to the Async I/O list
1537 //
1538 if (Event != NULL) {
1539 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1540 TransReq->CallerEvent = Event;
1541 InsertTailList (&Private->Queue, &TransReq->TransferList);
1542 gBS->RestoreTPL (OldTpl);
1543 }
1544
1545 //
1546 // Start to execute the transfer request.
1547 //
1548 UfsStartExecCmd (Private, TransReq->Slot);
1549
1550 //
1551 // Immediately return for async I/O.
1552 //
1553 if (Event != NULL) {
1554 return EFI_SUCCESS;
1555 }
1556
1557 //
1558 // Wait for the completion of the transfer request.
1559 //
1560 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << TransReq->Slot, 0, Packet->Timeout);
1561 if (EFI_ERROR (Status)) {
1562 goto Exit;
1563 }
1564
1565 //
1566 // Get sense data if exists
1567 //
1568 Response = (UTP_RESPONSE_UPIU*)((UINT8*)TransReq->CmdDescHost + TransReq->Trd->RuO * sizeof (UINT32));
1569 ASSERT (Response != NULL);
1570 SenseDataLen = Response->SenseDataLen;
1571 SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));
1572
1573 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {
1574 //
1575 // Make sure the hardware device does not return more data than expected.
1576 //
1577 if (SenseDataLen <= Packet->SenseDataLength) {
1578 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);
1579 Packet->SenseDataLength = (UINT8)SenseDataLen;
1580 } else {
1581 Packet->SenseDataLength = 0;
1582 }
1583 }
1584
1585 //
1586 // Check the transfer request result.
1587 //
1588 Packet->TargetStatus = Response->Status;
1589 if (Response->Response != 0) {
1590 DEBUG ((DEBUG_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));
1591 Status = EFI_DEVICE_ERROR;
1592 goto Exit;
1593 }
1594
1595 if (TransReq->Trd->Ocs == 0) {
1596 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
1597 if ((Response->Flags & BIT5) == BIT5) {
1598 ResTranCount = Response->ResTranCount;
1599 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
1600 Packet->InTransferLength -= ResTranCount;
1601 }
1602 } else {
1603 if ((Response->Flags & BIT5) == BIT5) {
1604 ResTranCount = Response->ResTranCount;
1605 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
1606 Packet->OutTransferLength -= ResTranCount;
1607 }
1608 }
1609 } else {
1610 Status = EFI_DEVICE_ERROR;
1611 }
1612
1613 Exit:
1614 UfsHc->Flush (UfsHc);
1615
1616 UfsStopExecCmd (Private, TransReq->Slot);
1617
1618 UfsReconcileDataTransferBuffer (Private, TransReq);
1619
1620 Exit1:
1621 if (TransReq->CmdDescMapping != NULL) {
1622 UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);
1623 }
1624 if (TransReq->CmdDescHost != NULL) {
1625 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (TransReq->CmdDescSize), TransReq->CmdDescHost);
1626 }
1627 if (TransReq != NULL) {
1628 FreePool (TransReq);
1629 }
1630 return Status;
1631 }
1632
1633 /**
1634 Send UIC command.
1635
1636 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1637 @param[in, out] UicCommand UIC command descriptor. On exit contains UIC command results.
1638
1639 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1640 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1641
1642 **/
1643 EFI_STATUS
1644 UfsExecUicCommands (
1645 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1646 IN OUT EDKII_UIC_COMMAND *UicCommand
1647 )
1648 {
1649 EFI_STATUS Status;
1650 UINT32 Data;
1651
1652 Status = UfsMmioRead32 (Private, UFS_HC_IS_OFFSET, &Data);
1653 if (EFI_ERROR (Status)) {
1654 return Status;
1655 }
1656
1657 if ((Data & UFS_HC_IS_UCCS) == UFS_HC_IS_UCCS) {
1658 //
1659 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1660 //
1661 Status = UfsMmioWrite32 (Private, UFS_HC_IS_OFFSET, Data);
1662 if (EFI_ERROR (Status)) {
1663 return Status;
1664 }
1665 }
1666
1667 //
1668 // When programming UIC command registers, host software shall set the register UICCMD
1669 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1670 // are set.
1671 //
1672 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG1_OFFSET, UicCommand->Arg1);
1673 if (EFI_ERROR (Status)) {
1674 return Status;
1675 }
1676
1677 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG2_OFFSET, UicCommand->Arg2);
1678 if (EFI_ERROR (Status)) {
1679 return Status;
1680 }
1681
1682 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG3_OFFSET, UicCommand->Arg3);
1683 if (EFI_ERROR (Status)) {
1684 return Status;
1685 }
1686
1687 //
1688 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1689 //
1690 Status = UfsWaitMemSet (Private, UFS_HC_STATUS_OFFSET, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);
1691 if (EFI_ERROR (Status)) {
1692 return Status;
1693 }
1694
1695 Status = UfsMmioWrite32 (Private, UFS_HC_UIC_CMD_OFFSET, UicCommand->Opcode);
1696 if (EFI_ERROR (Status)) {
1697 return Status;
1698 }
1699
1700 //
1701 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1702 // This bit is set to '1' by the host controller upon completion of a UIC command.
1703 //
1704 Status = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_UCCS, UFS_HC_IS_UCCS, UFS_TIMEOUT);
1705 if (EFI_ERROR (Status)) {
1706 return Status;
1707 }
1708
1709 if (UicCommand->Opcode != UfsUicDmeReset) {
1710 Status = UfsMmioRead32 (Private, UFS_HC_UCMD_ARG2_OFFSET, &UicCommand->Arg2);
1711 if (EFI_ERROR (Status)) {
1712 return Status;
1713 }
1714 Status = UfsMmioRead32 (Private, UFS_HC_UCMD_ARG3_OFFSET, &UicCommand->Arg3);
1715 if (EFI_ERROR (Status)) {
1716 return Status;
1717 }
1718 if ((UicCommand->Arg2 & 0xFF) != 0) {
1719 DEBUG_CODE_BEGIN();
1720 DumpUicCmdExecResult ((UINT8)UicCommand->Opcode, (UINT8)(UicCommand->Arg2 & 0xFF));
1721 DEBUG_CODE_END();
1722 return EFI_DEVICE_ERROR;
1723 }
1724 }
1725
1726 return EFI_SUCCESS;
1727 }
1728
1729 /**
1730 Allocate common buffer for host and UFS bus master access simultaneously.
1731
1732 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1733 @param[in] Size The length of buffer to be allocated.
1734 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
1735 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.
1736 @param[out] CmdDescMapping A resulting value to pass to Unmap().
1737
1738 @retval EFI_SUCCESS The common buffer was allocated successfully.
1739 @retval EFI_DEVICE_ERROR The allocation fails.
1740 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
1741
1742 **/
1743 EFI_STATUS
1744 UfsAllocateAlignCommonBuffer (
1745 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1746 IN UINTN Size,
1747 OUT VOID **CmdDescHost,
1748 OUT EFI_PHYSICAL_ADDRESS *CmdDescPhyAddr,
1749 OUT VOID **CmdDescMapping
1750 )
1751 {
1752 EFI_STATUS Status;
1753 UINTN Bytes;
1754 BOOLEAN Is32BitAddr;
1755 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
1756
1757 if ((Private->UfsHcInfo.Capabilities & UFS_HC_CAP_64ADDR) == UFS_HC_CAP_64ADDR) {
1758 Is32BitAddr = FALSE;
1759 } else {
1760 Is32BitAddr = TRUE;
1761 }
1762
1763 UfsHc = Private->UfsHostController;
1764 Status = UfsHc->AllocateBuffer (
1765 UfsHc,
1766 AllocateAnyPages,
1767 EfiBootServicesData,
1768 EFI_SIZE_TO_PAGES (Size),
1769 CmdDescHost,
1770 0
1771 );
1772 if (EFI_ERROR (Status)) {
1773 *CmdDescMapping = NULL;
1774 *CmdDescHost = NULL;
1775 *CmdDescPhyAddr = 0;
1776 return EFI_OUT_OF_RESOURCES;
1777 }
1778
1779 Bytes = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size));
1780 Status = UfsHc->Map (
1781 UfsHc,
1782 EdkiiUfsHcOperationBusMasterCommonBuffer,
1783 *CmdDescHost,
1784 &Bytes,
1785 CmdDescPhyAddr,
1786 CmdDescMapping
1787 );
1788
1789 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)))) {
1790 UfsHc->FreeBuffer (
1791 UfsHc,
1792 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),
1793 *CmdDescHost
1794 );
1795 *CmdDescHost = NULL;
1796 return EFI_OUT_OF_RESOURCES;
1797 }
1798
1799 if (Is32BitAddr && ((*CmdDescPhyAddr) > 0x100000000ULL)) {
1800 //
1801 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.
1802 //
1803 UfsHc->Unmap (
1804 UfsHc,
1805 *CmdDescMapping
1806 );
1807 UfsHc->FreeBuffer (
1808 UfsHc,
1809 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),
1810 *CmdDescHost
1811 );
1812 *CmdDescMapping = NULL;
1813 *CmdDescHost = NULL;
1814 return EFI_DEVICE_ERROR;
1815 }
1816
1817 ZeroMem (*CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)));
1818 return EFI_SUCCESS;
1819 }
1820
1821 /**
1822 Enable the UFS host controller for accessing.
1823
1824 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1825
1826 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1827 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1828
1829 **/
1830 EFI_STATUS
1831 UfsEnableHostController (
1832 IN UFS_PASS_THRU_PRIVATE_DATA *Private
1833 )
1834 {
1835 EFI_STATUS Status;
1836 UINT32 Data;
1837
1838 //
1839 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1840 //
1841 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1842 //
1843 Status = UfsMmioRead32 (Private, UFS_HC_ENABLE_OFFSET, &Data);
1844 if (EFI_ERROR (Status)) {
1845 return Status;
1846 }
1847
1848 if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {
1849 //
1850 // Write a 0 to the HCE register at first to disable the host controller.
1851 //
1852 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, 0);
1853 if (EFI_ERROR (Status)) {
1854 return Status;
1855 }
1856 //
1857 // Wait until HCE is read as '0' before continuing.
1858 //
1859 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
1860 if (EFI_ERROR (Status)) {
1861 return EFI_DEVICE_ERROR;
1862 }
1863 }
1864
1865 //
1866 // Write a 1 to the HCE register to enable the UFS host controller.
1867 //
1868 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN);
1869 if (EFI_ERROR (Status)) {
1870 return Status;
1871 }
1872
1873 //
1874 // Wait until HCE is read as '1' before continuing.
1875 //
1876 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);
1877 if (EFI_ERROR (Status)) {
1878 return EFI_DEVICE_ERROR;
1879 }
1880
1881 return EFI_SUCCESS;
1882 }
1883
1884 /**
1885 Detect if a UFS device attached.
1886
1887 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1888
1889 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1890 @retval EFI_NOT_FOUND Not found a UFS device attached.
1891 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1892
1893 **/
1894 EFI_STATUS
1895 UfsDeviceDetection (
1896 IN UFS_PASS_THRU_PRIVATE_DATA *Private
1897 )
1898 {
1899 UINTN Retry;
1900 EFI_STATUS Status;
1901 UINT32 Data;
1902 EDKII_UIC_COMMAND LinkStartupCommand;
1903
1904 //
1905 // Start UFS device detection.
1906 // Try up to 3 times for establishing data link with device.
1907 //
1908 for (Retry = 0; Retry < 3; Retry++) {
1909 LinkStartupCommand.Opcode = UfsUicDmeLinkStartup;
1910 LinkStartupCommand.Arg1 = 0;
1911 LinkStartupCommand.Arg2 = 0;
1912 LinkStartupCommand.Arg3 = 0;
1913 Status = UfsExecUicCommands (Private, &LinkStartupCommand);
1914 if (EFI_ERROR (Status)) {
1915 return EFI_DEVICE_ERROR;
1916 }
1917
1918 Status = UfsMmioRead32 (Private, UFS_HC_STATUS_OFFSET, &Data);
1919 if (EFI_ERROR (Status)) {
1920 return EFI_DEVICE_ERROR;
1921 }
1922
1923 if ((Data & UFS_HC_HCS_DP) == 0) {
1924 Status = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);
1925 if (EFI_ERROR (Status)) {
1926 return EFI_DEVICE_ERROR;
1927 }
1928 } else {
1929 return EFI_SUCCESS;
1930 }
1931 }
1932
1933 return EFI_NOT_FOUND;
1934 }
1935
1936 /**
1937 Initialize UFS task management request list related h/w context.
1938
1939 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1940
1941 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1942 @retval EFI_DEVICE_ERROR The initialization fails.
1943
1944 **/
1945 EFI_STATUS
1946 UfsInitTaskManagementRequestList (
1947 IN UFS_PASS_THRU_PRIVATE_DATA *Private
1948 )
1949 {
1950 UINT8 Nutmrs;
1951 VOID *CmdDescHost;
1952 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
1953 VOID *CmdDescMapping;
1954 EFI_STATUS Status;
1955
1956 //
1957 // Initial h/w and s/w context for future operations.
1958 //
1959 CmdDescHost = NULL;
1960 CmdDescMapping = NULL;
1961 CmdDescPhyAddr = 0;
1962
1963 //
1964 // Allocate and initialize UTP Task Management Request List.
1965 //
1966 Nutmrs = (UINT8) (RShiftU64 ((Private->UfsHcInfo.Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);
1967 Status = UfsAllocateAlignCommonBuffer (Private, Nutmrs * sizeof (UTP_TMRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);
1968 if (EFI_ERROR (Status)) {
1969 return Status;
1970 }
1971
1972 //
1973 // Program the UTP Task Management Request List Base Address and UTP Task Management
1974 // Request List Base Address with a 64-bit address allocated at step 6.
1975 //
1976 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLBA_OFFSET, (UINT32)(UINTN)CmdDescPhyAddr);
1977 if (EFI_ERROR (Status)) {
1978 return Status;
1979 }
1980
1981 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLBAU_OFFSET, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));
1982 if (EFI_ERROR (Status)) {
1983 return Status;
1984 }
1985 Private->UtpTmrlBase = CmdDescHost;
1986 Private->Nutmrs = Nutmrs;
1987 Private->TmrlMapping = CmdDescMapping;
1988
1989 //
1990 // Enable the UTP Task Management Request List by setting the UTP Task Management
1991 // Request List RunStop Register (UTMRLRSR) to '1'.
1992 //
1993 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLRSR_OFFSET, UFS_HC_UTMRLRSR);
1994 if (EFI_ERROR (Status)) {
1995 return Status;
1996 }
1997
1998 return EFI_SUCCESS;
1999 }
2000
2001 /**
2002 Initialize UFS transfer request list related h/w context.
2003
2004 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2005
2006 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
2007 @retval EFI_DEVICE_ERROR The initialization fails.
2008
2009 **/
2010 EFI_STATUS
2011 UfsInitTransferRequestList (
2012 IN UFS_PASS_THRU_PRIVATE_DATA *Private
2013 )
2014 {
2015 UINT8 Nutrs;
2016 VOID *CmdDescHost;
2017 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
2018 VOID *CmdDescMapping;
2019 EFI_STATUS Status;
2020
2021 //
2022 // Initial h/w and s/w context for future operations.
2023 //
2024 CmdDescHost = NULL;
2025 CmdDescMapping = NULL;
2026 CmdDescPhyAddr = 0;
2027
2028 //
2029 // Allocate and initialize UTP Transfer Request List.
2030 //
2031 Nutrs = (UINT8)((Private->UfsHcInfo.Capabilities & UFS_HC_CAP_NUTRS) + 1);
2032 Status = UfsAllocateAlignCommonBuffer (Private, Nutrs * sizeof (UTP_TRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);
2033 if (EFI_ERROR (Status)) {
2034 return Status;
2035 }
2036
2037 //
2038 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
2039 // Base Address with a 64-bit address allocated at step 8.
2040 //
2041 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLBA_OFFSET, (UINT32)(UINTN)CmdDescPhyAddr);
2042 if (EFI_ERROR (Status)) {
2043 return Status;
2044 }
2045
2046 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLBAU_OFFSET, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));
2047 if (EFI_ERROR (Status)) {
2048 return Status;
2049 }
2050
2051 Private->UtpTrlBase = CmdDescHost;
2052 Private->Nutrs = Nutrs;
2053 Private->TrlMapping = CmdDescMapping;
2054
2055 //
2056 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2057 // RunStop Register (UTRLRSR) to '1'.
2058 //
2059 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, UFS_HC_UTRLRSR);
2060 if (EFI_ERROR (Status)) {
2061 return Status;
2062 }
2063
2064 return EFI_SUCCESS;
2065 }
2066
2067 /**
2068 Initialize the UFS host controller.
2069
2070 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2071
2072 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
2073 @retval Others A device error occurred while initializing the controller.
2074
2075 **/
2076 EFI_STATUS
2077 UfsControllerInit (
2078 IN UFS_PASS_THRU_PRIVATE_DATA *Private
2079 )
2080 {
2081 EFI_STATUS Status;
2082
2083 Status = UfsEnableHostController (Private);
2084 if (EFI_ERROR (Status)) {
2085 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status));
2086 return Status;
2087 }
2088
2089 Status = UfsDeviceDetection (Private);
2090 if (EFI_ERROR (Status)) {
2091 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status));
2092 return Status;
2093 }
2094
2095 Status = UfsInitTaskManagementRequestList (Private);
2096 if (EFI_ERROR (Status)) {
2097 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status));
2098 return Status;
2099 }
2100
2101 Status = UfsInitTransferRequestList (Private);
2102 if (EFI_ERROR (Status)) {
2103 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status));
2104 return Status;
2105 }
2106
2107 DEBUG ((DEBUG_INFO, "UfsControllerInit Finished\n"));
2108 return EFI_SUCCESS;
2109 }
2110
2111 /**
2112 Stop the UFS host controller.
2113
2114 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2115
2116 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
2117 @retval Others A device error occurred while stopping the controller.
2118
2119 **/
2120 EFI_STATUS
2121 UfsControllerStop (
2122 IN UFS_PASS_THRU_PRIVATE_DATA *Private
2123 )
2124 {
2125 EFI_STATUS Status;
2126 UINT32 Data;
2127
2128 //
2129 // Enable the UTP Task Management Request List by setting the UTP Task Management
2130 // Request List RunStop Register (UTMRLRSR) to '1'.
2131 //
2132 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLRSR_OFFSET, 0);
2133 if (EFI_ERROR (Status)) {
2134 return Status;
2135 }
2136
2137 //
2138 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2139 // RunStop Register (UTRLRSR) to '1'.
2140 //
2141 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, 0);
2142 if (EFI_ERROR (Status)) {
2143 return Status;
2144 }
2145
2146 //
2147 // Write a 0 to the HCE register in order to disable the host controller.
2148 //
2149 Status = UfsMmioRead32 (Private, UFS_HC_ENABLE_OFFSET, &Data);
2150 if (EFI_ERROR (Status)) {
2151 return Status;
2152 }
2153 ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);
2154
2155 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, 0);
2156 if (EFI_ERROR (Status)) {
2157 return Status;
2158 }
2159
2160 //
2161 // Wait until HCE is read as '0' before continuing.
2162 //
2163 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
2164 if (EFI_ERROR (Status)) {
2165 return EFI_DEVICE_ERROR;
2166 }
2167
2168 DEBUG ((DEBUG_INFO, "UfsController is stopped\n"));
2169
2170 return EFI_SUCCESS;
2171 }
2172
2173 /**
2174 Internal helper function which will signal the caller event and clean up
2175 resources.
2176
2177 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data
2178 structure.
2179 @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data
2180 structure.
2181
2182 **/
2183 VOID
2184 EFIAPI
2185 SignalCallerEvent (
2186 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
2187 IN UFS_PASS_THRU_TRANS_REQ *TransReq
2188 )
2189 {
2190 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
2191 EFI_EVENT CallerEvent;
2192
2193 ASSERT ((Private != NULL) && (TransReq != NULL));
2194
2195 UfsHc = Private->UfsHostController;
2196 CallerEvent = TransReq->CallerEvent;
2197
2198 RemoveEntryList (&TransReq->TransferList);
2199
2200 UfsHc->Flush (UfsHc);
2201
2202 UfsStopExecCmd (Private, TransReq->Slot);
2203
2204 UfsReconcileDataTransferBuffer (Private, TransReq);
2205
2206 if (TransReq->CmdDescMapping != NULL) {
2207 UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);
2208 }
2209 if (TransReq->CmdDescHost != NULL) {
2210 UfsHc->FreeBuffer (
2211 UfsHc,
2212 EFI_SIZE_TO_PAGES (TransReq->CmdDescSize),
2213 TransReq->CmdDescHost
2214 );
2215 }
2216
2217 FreePool (TransReq);
2218
2219 gBS->SignalEvent (CallerEvent);
2220 return;
2221 }
2222
2223 /**
2224 Call back function when the timer event is signaled.
2225
2226 @param[in] Event The Event this notify function registered to.
2227 @param[in] Context Pointer to the context data registered to the Event.
2228
2229 **/
2230 VOID
2231 EFIAPI
2232 ProcessAsyncTaskList (
2233 IN EFI_EVENT Event,
2234 IN VOID *Context
2235 )
2236 {
2237 UFS_PASS_THRU_PRIVATE_DATA *Private;
2238 LIST_ENTRY *Entry;
2239 LIST_ENTRY *NextEntry;
2240 UFS_PASS_THRU_TRANS_REQ *TransReq;
2241 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet;
2242 UTP_RESPONSE_UPIU *Response;
2243 UINT16 SenseDataLen;
2244 UINT32 ResTranCount;
2245 UINT32 SlotsMap;
2246 UINT32 Value;
2247 EFI_STATUS Status;
2248
2249 Private = (UFS_PASS_THRU_PRIVATE_DATA*) Context;
2250 SlotsMap = 0;
2251
2252 //
2253 // Check the entries in the async I/O queue are done or not.
2254 //
2255 if (!IsListEmpty(&Private->Queue)) {
2256 EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->Queue) {
2257 TransReq = UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry);
2258 Packet = TransReq->Packet;
2259
2260 if ((SlotsMap & (BIT0 << TransReq->Slot)) != 0) {
2261 return;
2262 }
2263 SlotsMap |= BIT0 << TransReq->Slot;
2264
2265 Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Value);
2266 if (EFI_ERROR (Status)) {
2267 //
2268 // TODO: Should find/add a proper host adapter return status for this
2269 // case.
2270 //
2271 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR;
2272 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq->CallerEvent));
2273 SignalCallerEvent (Private, TransReq);
2274 continue;
2275 }
2276
2277 if ((Value & (BIT0 << TransReq->Slot)) != 0) {
2278 //
2279 // Scsi cmd not finished yet.
2280 //
2281 if (TransReq->TimeoutRemain > UFS_HC_ASYNC_TIMER) {
2282 TransReq->TimeoutRemain -= UFS_HC_ASYNC_TIMER;
2283 continue;
2284 } else {
2285 //
2286 // Timeout occurs.
2287 //
2288 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND;
2289 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq->CallerEvent));
2290 SignalCallerEvent (Private, TransReq);
2291 continue;
2292 }
2293 } else {
2294 //
2295 // Scsi cmd finished.
2296 //
2297 // Get sense data if exists
2298 //
2299 Response = (UTP_RESPONSE_UPIU*)((UINT8*)TransReq->CmdDescHost + TransReq->Trd->RuO * sizeof (UINT32));
2300 ASSERT (Response != NULL);
2301 SenseDataLen = Response->SenseDataLen;
2302 SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));
2303
2304 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {
2305 //
2306 // Make sure the hardware device does not return more data than expected.
2307 //
2308 if (SenseDataLen <= Packet->SenseDataLength) {
2309 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);
2310 Packet->SenseDataLength = (UINT8)SenseDataLen;
2311 } else {
2312 Packet->SenseDataLength = 0;
2313 }
2314 }
2315
2316 //
2317 // Check the transfer request result.
2318 //
2319 Packet->TargetStatus = Response->Status;
2320 if (Response->Response != 0) {
2321 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq->CallerEvent));
2322 SignalCallerEvent (Private, TransReq);
2323 continue;
2324 }
2325
2326 if (TransReq->Trd->Ocs == 0) {
2327 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
2328 if ((Response->Flags & BIT5) == BIT5) {
2329 ResTranCount = Response->ResTranCount;
2330 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
2331 Packet->InTransferLength -= ResTranCount;
2332 }
2333 } else {
2334 if ((Response->Flags & BIT5) == BIT5) {
2335 ResTranCount = Response->ResTranCount;
2336 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
2337 Packet->OutTransferLength -= ResTranCount;
2338 }
2339 }
2340 } else {
2341 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq->CallerEvent));
2342 SignalCallerEvent (Private, TransReq);
2343 continue;
2344 }
2345
2346 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq->CallerEvent));
2347 SignalCallerEvent (Private, TransReq);
2348 }
2349 }
2350 }
2351 }
2352
2353 /**
2354 Initializes UfsHcInfo field in private data.
2355
2356 @param[in] Private Pointer to host controller private data.
2357
2358 @retval EFI_SUCCESS UfsHcInfo initialized successfully.
2359 @retval Others Failed to initalize UfsHcInfo.
2360 **/
2361 EFI_STATUS
2362 GetUfsHcInfo (
2363 IN UFS_PASS_THRU_PRIVATE_DATA *Private
2364 )
2365 {
2366 UINT32 Data;
2367 EFI_STATUS Status;
2368
2369 Status = UfsMmioRead32 (Private, UFS_HC_VER_OFFSET, &Data);
2370 if (EFI_ERROR (Status)) {
2371 return Status;
2372 }
2373
2374 Private->UfsHcInfo.Version = Data;
2375
2376 Status = UfsMmioRead32 (Private, UFS_HC_CAP_OFFSET, &Data);
2377 if (EFI_ERROR (Status)) {
2378 return Status;
2379 }
2380
2381 Private->UfsHcInfo.Capabilities = Data;
2382
2383 return EFI_SUCCESS;
2384 }
2385