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